计算机图形学常用算法及代码大全
MFC实现计算机图形学算法

MFC实现计算机图形学算法⽬录1.直线算法1.1 DDAvoid ChuituView::OnDDA(){// TODO: 在此添加命令处理程序代码dlg_line dlg;dlg.DoModal();CDC* pDC = GetDC();CRect rect;GetClientRect(&rect);//重定义坐标轴Axis(pDC, rect);pDC->TextOut(450, 18, _T("DDA画线法成功了!"));//在屏幕(450,18)的位置显⽰⼀个⽩⾊底⾊的⿊字:DDA画线法成功了!double dx, dy, e, x, y;dx = dlg.x2 - dlg.x1;dy = dlg.y2 - dlg.y1;e = (fabs(dx) > fabs(dy) ? fabs(dx) : fabs(dy));dx /= e;dy /= e;x = dlg.x1;y = dlg.y1;for (int i = 1; i <= e; ++i) {pDC->SetPixel(int(x + 0.5), int(y + 0.5), RGB(255, 0, 0));x += dx;y += dy;}}1.2 中点法void ChuituView::OnMidpointline(){// TODO: 在此添加命令处理程序代码dlg_line dlg;dlg.DoModal();float x, y, xa, xb, ya, yb;xa = dlg.x1, ya = dlg.y1;xb = dlg.x2; yb = dlg.y2;float d, k;CDC* pDC = GetDC();CRect rect;GetClientRect(&rect);//重定义坐标轴Axis(pDC, rect);pDC->TextOut(450, 18, _T("中点画线法成功了!"));k = (yb - ya) / (xb - xa);y = ya, x = xa;d = 0.5 - k;for (x = xa; x <= xb; x++){if (d < 0){y = y + 1; d = d + 1 - k;}else{y = y; d = d - k;}pDC->SetPixel(x, y, RGB(0, 0, 255));}}1.3Bresenham法void ChuituView::OnBresenhamline_1(int x0, int y0, int x1, int y1){// TODO: 在此处添加实现代码.CDC* pDC = GetDC();pDC->TextOut(450, 70, _T("请⽤⿏标划线!"));// TODO: 在此添加命令处理程序代码int color = 255;int x, y, e;int dx = x1 - x0;//x偏移量int dy = y1 - y0;//y偏移量int ux = dx > 0 ? 1 : -1;//x伸展⽅向int uy = dy > 0 ? 1 : -1;//y伸展⽅向int dx2 = abs(dx << 1);//x偏移量乘2int dy2 = abs(dy << 1);//y偏移量乘2if (abs(dx) > abs(dy))//以x为增量⽅向计算{int e = -dx; //e = -0.5 * 2 * dx,把e ⽤2 * dx* e替换int x = x0;//起点x坐标int y = y0;//起点y坐标while (x != x1 + ux){//printf("%d,%d\n", x, y);pDC->SetPixel(x, y, color);e = e + dy2;//来⾃ 2*e*dx= 2*e*dx + 2dy (原来是 e = e + k)if (e > 0)//e是整数且⼤于0时表⽰要取右上的点(否则是右下的点) {if (y != y1){y += uy;}e = e - dx2;//2*e*dx = 2*e*dx - 2*dx (原来是 e = e -1)}x += ux;}}else{//以y为增量⽅向计算int e = -dy; //e = -0.5 * 2 * dy,把e ⽤2 * dy* e替换int x = x0;//起点x坐标int y = y0;//起点y坐标while (y != y1 + uy){//printf("%d,%d\n", x, y);pDC->SetPixel(x, y, color);e = e + dx2;//来⾃ 2*e*dy= 2*e*dy + 2dy (原来是 e = e + k)if (e > 0)//e是整数且⼤于0时表⽰要取右上的点(否则是右下的点) {if (x != x1){x += ux;}e = e - dy2;//2*e*dy = 2*e*dy - 2*dy (原来是 e = e -1)}y += uy;}}}void ChuituView::OnBresenhamline(){CDC* pDC = GetDC();state = 1;pDC->TextOut(450, 70, _T("请⽤⿏标划线!"));}2.圆2.1中点法void ChuituView::OnMidpointcircle(){// TODO: 在此添加命令处理程序代码dlg_circle dlg;dlg.DoModal();CDC* pDC = GetDC();CRect rect;GetClientRect(&rect);//重定义坐标轴Axis(pDC, rect);int r = dlg.circle_r;int x0 =dlg.circle_x, y0 = dlg.circle_y;double d;int x = 0;int y = r;d = 1 - r;int color = 255;//pDC->SetPixel(x, y, color);while (x < y){pDC->SetPixel(x + x0, y + y0, color);pDC->SetPixel(-x + x0, y + y0, color);pDC->SetPixel(-x + x0, -y + y0, color);pDC->SetPixel(x + x0, -y + y0, color);pDC->SetPixel(y + x0, x + y0, color);pDC->SetPixel(-y + x0, x + y0, color);pDC->SetPixel(-y + x0, -x + y0, color);pDC->SetPixel(y + x0, -x + y0, color);if (d < 0){d += 2 * x;++x;}else{d += 2 * (x - y) + 5;++x;--y;}//pDC->SetPixel(x, y, 255);}}1.2 Bresenham法void ChuituView::Bresenhamcircle_1(int x0, int y0, int r){// TODO: 在此处添加实现代码.CDC *pDC = GetDC();int color = 255;int x = 0;int y = r;int d = 1 - r;while (x <= y){pDC->SetPixel(x + x0, y + y0, color);pDC->SetPixel(-x + x0, y + y0, color);pDC->SetPixel(-x + x0, -y + y0, color);pDC->SetPixel(x + x0, -y + y0, color);pDC->SetPixel(y + x0, x + y0, color);pDC->SetPixel(-y + x0, x + y0, color);pDC->SetPixel(-y + x0, -x + y0, color);pDC->SetPixel(y + x0, -x + y0, color);if (d < 0)d += 2 * x + 3;else{d += 2 * (x - y) + 5;y--;}x++;}}void ChuituView::OnBresenhamcircle(){// TODO: 在此添加命令处理程序代码CDC *pDC = GetDC();pDC->TextOut(450, 70, _T("请⽤⿏标划线以确定远点坐标和半径!"));state = 2;}3.椭圆(Bresenhame)void ChuituView::OnBresenhamellipse(){// TODO: 在此添加命令处理程序代码CRect rect;GetClientRect(&rect);CDC* pDC = GetDC();//重定义坐标轴Axis(pDC, rect);pDC->TextOut(400, 70, _T("这是⼀个长半轴为200,短半轴100的椭圆!"));int a = 200, b = 100, color = 255, x, y;float d1;float d2 = 0;x = 0; y = b;d1 = b * b + a * a*(-b + 0.25);pDC->SetPixel(x, y, color);pDC->SetPixel(-x, -y, color);pDC->SetPixel(-x, y, color);pDC->SetPixel(x, -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--;}pDC->SetPixel(x, y, color);pDC->SetPixel(-x, -y, color);pDC->SetPixel(-x, y, color);pDC->SetPixel(x, -y, color);}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--;}pDC->SetPixel(x, y, color);pDC->SetPixel(-x, -y, color);pDC->SetPixel(-x, y, color);pDC->SetPixel(x, -y, color);}}4.直线扫描//直线扫描void ChuituView::OnPolygonscan(){// TODO: 在此添加命令处理程序代码CDC* pDC = GetDC();const int POINTNUM = 6;typedef struct XET{float x;float dx, ymax;XET* next;}AET, NET;struct point{float x;float y;}polypoint[POINTNUM] = { 250, 50, 550, 150, 550, 400, 250, 250, 100, 350, 100, 100 };int MaxY = 0;int i;for (i = 0; i < POINTNUM; i++)if (polypoint[i].y > MaxY)MaxY = polypoint[i].y;AET *pAET = new AET;pAET->next = NULL;NET *pNET[1024];for (i = 0; i <= MaxY; i++){pNET[i] = new NET;pNET[i]->next = NULL;}for (i = 0; i <= MaxY; i++){for (int j = 0; j < POINTNUM; j++)if (polypoint[j].y == i){if (polypoint[(j - 1 + POINTNUM) % POINTNUM].y > polypoint[j].y){NET *p = new NET;p->x = polypoint[j].x;p->ymax = polypoint[(j - 1 + POINTNUM) % POINTNUM].y;p->dx = (polypoint[(j - 1 + POINTNUM) % POINTNUM].x - polypoint[j].x) / (polypoint[(j - 1 + POINTNUM) % POINTNUM].y - polypoint[j].y);p->next = pNET[i]->next;pNET[i]->next = p;}if (polypoint[(j + 1 + POINTNUM) % POINTNUM].y > polypoint[j].y){NET *p = new NET;p->x = polypoint[j].x;p->ymax = polypoint[(j + 1 + POINTNUM) % POINTNUM].y;p->dx = (polypoint[(j + 1 + POINTNUM) % POINTNUM].x - polypoint[j].x) / (polypoint[(j + 1 + POINTNUM) % POINTNUM].y - polypoint[j].y);p->next = pNET[i]->next;pNET[i]->next = p;}}}for (i = 0; i <= MaxY; i++){NET *p = pAET->next;while (p){p->x = p->x + p->dx;p = p->next;}AET *tq = pAET;p = pAET->next;tq->next = NULL;while (p){while (tq->next && p->x >= tq->next->x)tq = tq->next;NET *s = p->next;p->next = tq->next;tq->next = p;p = s;tq = pAET;}AET *q = pAET;p = q->next;while (p){if (p->ymax == i){q->next = p->next;delete p;p = q->next;}else{q = q->next;p = q->next;}}p = pNET[i]->next;q = pAET;while (p){while (q->next && p->x >= q->next->x)q = q->next;NET *s = p->next;p->next = q->next;q->next = p;p = s;q = pAET;}p = pAET->next;while (p && p->next){for (float j = p->x; j <= p->next->x; j++)pDC->SetPixel(static_cast<int>(j), i, RGB(255, 0, 0));p = p->next->next;//考虑端点情况}}}5.种⼦填充5.1 四领域//四领域void ChuituView::OnPolygonfloodfill4(){// TODO: 在此添加命令处理程序代码CClientDC dc1(this);for (int i = 0; i <= 60; i++){dc1.SetPixel(0, i, 200);}for (int i = 0; i <= 60; i++)dc1.SetPixel(i, 0, 200);for (int i = 0; i <= 60; i++)dc1.SetPixel(i, 60, 200);for (int i = 0; i <= 60; i++)dc1.SetPixel(60, i, 200);FloodFill4(20, 20, 200, 100);}void ChuituView::FloodFill4(int x, int y, int oldColor, int newColor){CClientDC dc(this);int color;color = dc.GetPixel(x, y);if ((color != oldColor) && color != newColor){dc.SetPixel(x, y, newColor);FloodFill4(x, y + 1, oldColor, newColor);FloodFill4(x, y - 1, oldColor, newColor);FloodFill4(x - 1, y, oldColor, newColor);FloodFill4(x + 1, y, oldColor, newColor);}}5.1⼋领域//⼋领域void ChuituView::OnPolygonfloodfill8(){// TODO: 在此添加命令处理程序代码CClientDC dc1(this);for (int i = 0; i <= 50; i++){dc1.SetPixel(0, i, 200);}for (int i = 0; i <= 50; i++)dc1.SetPixel(i, 0, 200);for (int i = 0; i <= 50; i++)dc1.SetPixel(i, 50, 200);for (int i = 0; i <= 50; i++)dc1.SetPixel(50, i, 200);FloodFill8(6, 6, 200, 250);}void ChuituView::FloodFill8(int x, int y, int oldColor, int newColor){CClientDC dc(this);int color;color = dc.GetPixel(x, y);if ((color != oldColor) && color != newColor){dc.SetPixel(x, y, newColor);FloodFill8(x, y + 1, oldColor, newColor);FloodFill8(x, y - 1, oldColor, newColor);FloodFill8(x - 1, y, oldColor, newColor);FloodFill8(x + 1, y, oldColor, newColor);FloodFill8(x + 1, y + 1, oldColor, newColor);FloodFill8(x - 1, y - 1, oldColor, newColor);FloodFill8(x + 1, y - 1, oldColor, newColor);FloodFill8(x - 1, y + 1, oldColor, newColor);}}6.⼆维⼏何变换-五种基本变换6.1 平移//平移void ChuituView::Onpingyi2(){// TODO: 在此添加命令处理程序代码CClientDC dc(this);CRect rect;GetClientRect(&rect);//返回的是设备坐标,⽽SetViewportOrg需要的也是设备坐标,故此处不⽤转换 dc.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);int Tx = 100, Ty = 200;//x平移100,y平移200int a[4][2] = { 0, 0, 100, 0, 100, 100, 0, 0 };//确定三⾓形的形状dc.TextOut(100, 0, (CString)"原图形");for (int i = 0; i < 3; i++){dc.MoveTo(a[i][0], a[i][1]);dc.LineTo(a[i + 1][0], a[i + 1][1]);}CPen pen;pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));dc.SelectObject(&pen);dc.TextOut(100 + Tx, Ty, (CString)"平移后图形");for (int i = 0; i < 3; i++){dc.MoveTo(a[i][0] + Tx, a[i][1] + Ty);dc.LineTo(a[i + 1][0] + Tx, a[i + 1][1] + Ty);}}6.2旋转//旋转void ChuituView::Onxuanzhaun2(){// TODO: 在此添加命令处理程序代码CClientDC dc(this);CRect rect;GetClientRect(&rect);//返回的是设备坐标,⽽SetViewportOrg需要的也是设备坐标,故此处不⽤转换 dc.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);float o = 3.1415926 / 2; //旋转90度float c = cos(o);float s = sin(o);int Tx = 300;int a[4][2] = { 0, 0, 100, 0, 100, 100, 0, 0 };//确定三⾓形的形状dc.TextOut(100, 0, (CString)"原图形");for (int i = 0; i < 3; i++){dc.MoveTo(a[i][0], a[i][1]);dc.LineTo(a[i + 1][0], a[i + 1][1]);}CPen pen;pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));dc.SelectObject(&pen);dc.TextOut(100 * c + Tx, 0, (CString)"旋转后图形");for (int i = 0; i < 3; i++){dc.MoveTo(a[i][0] * c - a[i][1] * s + Tx, a[i][0] * s + a[i][0] * c);dc.LineTo(a[i + 1][0] * c - a[i + 1][1] * s + Tx, a[i + 1][0] * s + a[i + 1][0] * c);}}6.3错切//错切void ChuituView::Oncuoqie2(){// TODO: 在此添加命令处理程序代码CClientDC dc(this);CRect rect;GetClientRect(&rect);//返回的是设备坐标,⽽SetViewportOrg需要的也是设备坐标,故此处不⽤转换 dc.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);int b = 2, c = 2;int Tx = 300;int a[4][2] = { 0, 0, 100, 0, 100, 100, 0, 0 };//确定三⾓形的形状dc.TextOut(100, 0, (CString)"原图形");for (int i = 0; i < 3; i++){dc.MoveTo(a[i][0], a[i][1]);dc.LineTo(a[i + 1][0], a[i + 1][1]);}CPen pen;pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));dc.SelectObject(&pen);dc.TextOut(100 + Tx, 0, (CString)"错切后图形");for (int i = 0; i < 3; i++){dc.MoveTo(a[i][0] + c * a[i][1] + Tx, b * a[i][0] + a[i][1]);dc.LineTo(a[i + 1][0] + c * a[i + 1][1] + Tx, b * a[i + 1][0] + a[i + 1][1]);}}6.4⽐例//⽐例void ChuituView::Onbili2(){// TODO: 在此添加命令处理程序代码CClientDC dc(this);CRect rect;GetClientRect(&rect);//返回的是设备坐标,⽽SetViewportOrg需要的也是设备坐标,故此处不⽤转换 dc.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);int Tx = 300;int Sx = 3, Sy = 4; //放⼤缩⼩⽐例int a[4][2] = { 0, 0, 100, 0, 100, 100, 0, 0 };//确定三⾓形的形状dc.TextOut(100, 0, (CString)"原图形");for (int i = 0; i < 3; i++){dc.MoveTo(a[i][0], a[i][1]);dc.LineTo(a[i + 1][0], a[i + 1][1]);}CPen pen;pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));dc.SelectObject(&pen);dc.TextOut(100 + Tx, 0, (CString)"⽐例变换后图形");for (int i = 0; i < 3; i++){dc.MoveTo(a[i][0] * Sx + Tx, a[i][1] * Sy);dc.LineTo(a[i + 1][0] * Sx + Tx, a[i + 1][1] * Sy);}}6.5对称//对称void ChuituView::Onduichen2(){// TODO: 在此添加命令处理程序代码CClientDC dc(this);CRect rect;GetClientRect(&rect);//返回的是设备坐标,⽽SetViewportOrg需要的也是设备坐标,故此处不⽤转换 dc.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);int a[4][2] = { 0, 0, 100, 0, 100, 100, 0, 0 };//确定三⾓形的形状dc.TextOut(100, 0, (CString)"原图形");for (int i = 0; i < 3; i++){dc.MoveTo(a[i][0], a[i][1]);dc.LineTo(a[i + 1][0], a[i + 1][1]);}CPen pen;pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));dc.SelectObject(&pen);dc.TextOut(-100, -0, (CString)"对称后图形");for (int i = 0; i < 3; i++){dc.MoveTo(-a[i][0], -a[i][1]);dc.LineTo(-a[i + 1][0], -a[i + 1][1]);}}7.裁剪7.1直线cohen-sutherland法//直线cohen-sutherland法unsigned int ChuituView::EnCode(CPoint point){#define D0 1 //0001#define D1 2 //0010#define D2 4 //0100#define D3 8 //1000// TODO: 在此处添加实现代码.int C1 = 0;if (point.x < wxl)C1 = C1 | D0;if (point.x > wxr)C1 = C1 | D1;if (point.y < wyb)C1 = C1 | D2;if (point.y > wyt)C1 = C1 | D3;return C1;}void ChuituView::Oncs_line(){// TODO: 在此添加命令处理程序代码CDC* pDC = GetDC();ChuituDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);if (!pDoc)return;// wxl为左侧裁剪边,wxr为右侧裁剪边,wyb为下侧裁剪边,wyt为上裁剪边。
计算机图形学编程

1:角度DDA法绘制椭圆的程序:V oid line DDA(int x1,int y1,int x2,int y2,int color) x=x0+acost;y=y0+bsint { if{abs(x2-x1)>=abs(y2-y1);dm=abs(x2-x1)}Else { dm=abs(y2-y1)}float dx=(float)(x2-x1)/dm;float x=(float)(x1+0.5);float y=(float)(y1+0.5);for (int i=0;i<dm;i++)Setpixel(int x,int y,int color)x+=dx;y+=dy;}}2:绘制抛物线的程序:Par (int xs,int ys,int xm,int ym,int xe,int ye){double d,d1,ax,bx,by;int n,i;ax=(xe-2*xm+xs)*2.0;ay=(ye-2*ym+ys)*2.0;bx=xe-xs-ax;by=ye-ys-ay;n=sqrt(ax*ax+ay*ay);d=1.0/n;d1=d;for(i=0;i<=n;i++){ lineto((ax*d1+bx*d1+xs),(ay*d1*d1+by*d1+ys);d1+=d;}Lineto(xe,ye);}3:绘制三次Hermite曲线的程序:(给出四个点P0,P1,P2,P3,要在P1和P2之间绘一条Hermite曲线,用向量P0P1作为P1处的切线向量,用P2P3作为P2处的切线矢量)V oid HermiteCurve(Point po,Point p1,Point p2,Point p3,int count){Point r1,r2; //切线矢量r1=p1-p0; //调用重载r2=p3-p2;double t=0.0; dt=1.0/count;moveto(p1.x,p1.y);//设置起点for(int i=0;i<count+1;i++){double tt=t*t; double ttt=t*t*t;Double F1,F2,F3,F4; //调和函数F1=2*ttt-3*tt+1; F2=-2*ttt+3*tt; F3=ttt-2*tt+t; F4=ttt-tt;double x=p1.x*F1+p2.x*F2+r1.x*F3+r2.x*F4;double x=p1.y*F1+p2.y*F2+r1.y*F3+r2.y*F4;Lineto(x,y);t+=dt;}}4:绘制三次Bezier曲线和三次B样条曲线的程序(以四个点P0,P1,P2,P3作为控制多边形)V oid BezierCurve(Point p0,Pint p1,Point p2,Point p3,int count){double t=0.0; dt=1.0/count;moveto(p1.x, p1.y);//设置起点for(int i=0; i<count+1;i++){ double F1,F2,F3,F4,x,y;//调和函数double u=1.0-t;F1=u*u*u; F2=3*t*u*u; F3=3*t*t*u; F4=t*t*t;x=p0.x*F1+p1.x+F2+p2.x*F3+p3.x*F4;y=po.y*F1+p1.y*F2+p2.y*F3+p3.y*F4;Lineto(x,y);t+=dt;}}Void B_SpLine((Point p0,Pint p1,Point p2,Point p3,int count){double t=0.0;dt=1.0/count;For (int i=0;i<count+1;i++){ double tt=t*t; double ttt=tt*t;Double F1,F2,F3,F4;//调和函数F1=-ttt+3*tt-3*t+1; F2=3*ttt-6*tt+4;F3=-3*ttt+3*tt+3*t+1; F4=ttt;x=p0.x*F1+p1.x*F2+p2.x*F3+p3.x*F4;y=p0.y*F1+p1.y*F2+p2.y*F3+p3.y*F4;x/=6.0; y/=6.0;if(i==0) moveto(x,y);else lineto(x,y);t+=dt;}}5:写出光线跟踪算法(Ray-Tracing算法)的伪代码Color TraceRay(start,direction,depth)Vector start,directionInt depth{if (depth>MAX_DEPTH)color=黑色;else{ 光线与物体求交,找出离start最近的交点;If(无交点)color=背景色;Else{ local——color=用局部光照模型计算出交点处的光强;计算反射方向:R=1+2Ncosθ;Reflected_color=TraceRay(交点,反射方向R,depth+1);计算折射方向: T= (1/η)I-(cosθ2-(1/η)cosθ1)N;Transmitted_color=TraceRay(交点,折射方向,depth+1);Color=combine(local_color,Reflected_color,Kr,transmitted_color,KT)}}Return(color);}6:借助栈数据结构,写出漫水法区域填充的程序。
计算机图形学常用算法及代码大全

2。
1。
1 生成直线的DDA算法数值微分法即DDA法(Digital Differential Analyzer),是一种基于直线的微分方程来生成直线的方法.一、直线DDA算法描述:设(x1,y1)和(x2,y2)分别为所求直线的起点和终点坐标,由直线的微分方程得= m =直线的斜率(2-1)可通过计算由x方向的增量△x引起y的改变来生成直线:x i+1=x i+△x (2-2)y i+1=y i+△y=y i+△x·m (2-3) 也可通过计算由y方向的增量△y引起x的改变来生成直线:y i+1=y i+△y (2-4)x i+1=x i+△x=x i+△y/m (2-5) 式(2-2)至(2-5)是递推的.二、直线DDA算法思想:选定x2-x1和y2-y1中较大者作为步进方向(假设x2-x1较大),取该方向上的增量为一个象素单位(△x=1),然后利用式(2-1)计算另一个方向的增量(△y=△x·m=m)。
通过递推公式(2-2)至(2-5),把每次计算出的(x i+1,y i+1)经取整后送到显示器输出,则得到扫描转换后的直线。
之所以取x2-x1和y2-y1中较大者作为步进方向,是考虑沿着线段分布的象素应均匀,这在下图中可看出。
另外,算法实现中还应注意直线的生成方向,以决定Δx及Δy是取正值还是负值。
三、直线DDA算法实现:1、已知直线的两端点坐标:(x1,y1),(x2,y2)2、已知画线的颜色:color3、计算两个方向的变化量:dx=x2-x1dy=y2-y14、求出两个方向最大变化量的绝对值:steps=max(|dx|,|dy|)5、计算两个方向的增量(考虑了生成方向):xin=dx/stepsyin=dy/steps6、设置初始象素坐标:x=x1,y=y17、用循环实现直线的绘制:for(i=1;i〈=steps;i++){putpixel(x,y,color);/*在(x,y)处,以color色画点*/x=x+xin;y=y+yin;}五、直线DDA算法特点:该算法简单,实现容易,但由于在循环中涉及实型数的运算,因此生成直线的速度较慢。
C语言之图形学算法

C语言之图形学算法图形学算法是计算机图形学领域中的重要内容,它涉及到图形的创建、显示和处理等方面。
在C语言中,有一些常用的图形学算法可以帮助我们实现各种各样的图形效果。
本文将介绍一些常见的C语言图形学算法,包括直线绘制算法、圆绘制算法和多边形填充算法等。
一、直线绘制算法直线是图形学中最基础的图形之一,其绘制算法也是最简单的。
在C语言中,常用的直线绘制算法有DDA算法和Bresenham算法。
1. DDA算法DDA(Digital Differential Analyzer)算法是一种直线绘制算法,其基本思想是通过计算直线的斜率和每个像素点之间的差值来实现直线的绘制。
下面是DDA算法的伪代码:```dx = x2 - x1dy = y2 - y1step = max(abs(dx), abs(dy))x_increment = dx / stepy_increment = dy / stepx = x1y = y1plot(x, y)for i in range(step):x = x + x_incrementy = y + y_incrementplot(round(x), round(y))```2. Bresenham算法Bresenham算法是一种更加高效的直线绘制算法,它通过利用整数运算和误差累积的方式来实现直线的绘制。
下面是Bresenham算法的伪代码:```dx = abs(x2 - x1)dy = abs(y2 - y1)if dx > dy:step = dxelse:step = dyx_increment = dx / stepy_increment = dy / stepy = y1plot(x, y)for i in range(step):if dx > dy:x = x + x_incrementelse:y = y + y_incrementplot(round(x), round(y))```二、圆绘制算法圆是一种常见的图形,在计算机图形学中,圆的绘制算法也是一个重要的问题。
计算机图形学代码

四、实验结果抓图与分析1、目标的平移的源程序2、绕任意点旋转的源程序实验一、直线的生成一、实验内容根据提供的程序框架,修改部分代码,完成画一条直线的功能(中点画线法或者Bresenham画线法任选一),只要求实现在第一象限内的直线。
二、算法原理介绍双击直线生成.dsw打开给定的程序,或者先启动VC++,文件(file)→打开工作空间(open workspace)。
打开直线生成view.cpp,按注释改写下列函数:1.void CMyView::OnDdaline() (此为DDA生成直线)2.void CMyView::OnBresenhamline()(此为Bresenham画直线)3.void CMYView::OnMidPointLine()(此为中点画线法)三、程序源代码1.DDA生成直线画法程序:float x,y,dx,dy,k;dx=(float)(xb-xa);dy=(float)(yb-ya);k=dy/dx;x=xa;y=ya;if(abs(k)<1){for (x=xa;x<=xb;x++){pdc->SetPixel(x, int(y+0.5),COLOR);y=y+k;}}if(abs(k)>=1){for(y=ya;y<=yb;y++){pdc->SetPixel(int(x+0.5),y,COLOR);x=x+1/k;}}//DDA画直线结束}2.Bresenham画直线源程序:float b,d,xi,yi;int i;float k;k=(yb-ya)/(xb-xa);b=(ya*xb-yb*xa)/(xb-xa);if(k>0&&k<=1)for(i=0;i<abs(xb-xa);i++){ d=ya+0.5-k*(xa+1)-b;if(d>=0){ xi=xa+1;yi=ya;xa++;ya=ya+0.5;}if(d<0){ xi=xa+1;yi=ya+1;xa++;ya=ya+1.5;}pdc->SetPixel(xi,yi,COLOR); }//BresenHam画直线结束}3.中点画线法源程序:float b,d,xi,yi;int i;float k;k=(yb-ya)/(xb-xa);b=(ya*xb-yb*xa)/(xb-xa);if(k>0&&k<=1)for(i=0;i<abs(xb-xa);i++){ d=ya+0.5-k*(xa+1)-b;if(d>=0){ xi=xa+1;yi=ya;xa++;ya=ya+0.5;}if(d<0){ xi=xa+1;yi=ya+1;xa++;ya=ya+1.5;}pdc->SetPixel(xi,yi,COLOR); }//BresenHam画直线结束}四、实验结果抓图与分析1、DDA生成直线2、Bresenham画直线3、中点画线法实验二、bresenham画圆一、实验内容根据提供的程序框架,修改部分代码,用Bresenham画法画一段圆弧或者画圆。
计算机图形学DDA算法程序代码

计算机图形学DDA算法程序代码// Experiment_Frame_OneView.cpp : implementation of the CExperiment_Frame_OneView class //#include "stdafx.h"#include "Experiment_Frame_One.h"#include "Experiment_Frame_OneDoc.h"#include "Experiment_Frame_OneView.h"#include "SettingDlg.h"#include "InputDialog.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////// //////////// CExperiment_Frame_OneViewIMPLEMENT_DYNCREATE(CExperiment_Frame_OneView, CView)BEGIN_MESSAGE_MAP(CExperiment_Frame_OneView, CView)//{{AFX_MSG_MAP(CExperiment_Frame_OneView)ON_COMMAND(IDM_SETTING, OnSetting)ON_COMMAND(IDM_INPUT, OnInput)//}}AFX_MSG_MAP// Standard printing commandsON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW,CView::OnFilePrintPreview)END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////// //////////// CExperiment_Frame_OneView construction/destructionCExperiment_Frame_OneView::CExperiment_Frame_OneVie w(){// TODO: add construction code herem_bGridOn = true;m_iMarginSize = 20;m_iPointSize = 20;m_iActive_Algorithm = 0;m_PointColor = RGB(255, 0, 0);X0 = Y0 = 0;X1 = Y1 = 10;}CExperiment_Frame_OneView::~CExperiment_Frame_OneVi ew(){}BOOLCExperiment_Frame_OneView::PreCreateWindow(CREA TESTRUCT& cs) {// TODO: Modify the Window class or styles here by modifying// the CREATESTRUCT csreturn CView::PreCreateWindow(cs);}/////////////////////////////////////////////////////////////////////////////// CExperiment_Frame_OneView drawingvoid CExperiment_Frame_OneView::OnDraw(CDC* pDC){CExperiment_Frame_OneDoc* pDoc = GetDocument();ASSERT_V ALID(pDoc);// TODO: add draw code for native data hereif( this->m_bGridOn ){this->DrawGrid(pDC);}switch( this->m_iActive_Algorithm) {case 0: //DDADDA(X0,Y0,X1,Y1);break;case 1: //Mid_BresenhamMid_Bresenham(X0,Y0,X1,Y1);break;default:break;}CView::OnDraw(pDC);}/////////////////////////////////////////////////////////////////// //////////// CExperiment_Frame_OneView printingBOOLCExperiment_Frame_OneView::OnPreparePrinting(CPrintInfo* pInfo){// default preparationreturn DoPreparePrinting(pInfo);}void CExperiment_Frame_OneView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) {// TODO: add extra initialization before printing}void CExperiment_Frame_OneView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) {// TODO: add cleanup after printing}/////////////////////////////////////////////////////////////////// //////////// CExperiment_Frame_OneView diagnostics#ifdef _DEBUGvoid CExperiment_Frame_OneView::AssertV alid() const{CView::AssertValid();}void CExperiment_Frame_OneView::Dump(CDumpContext& dc) const{CView::Dump(dc);}CExperiment_Frame_OneDoc*CExperiment_Frame_OneView::GetDocument() // non-debug version is inline{ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CExperi ment_Frame_OneDoc)));return (CExperiment_Frame_OneDoc*)m_pDocument;}#endif //_DEBUG/////////////////////////////////////////////////////////////////// //////////// CExperiment_Frame_OneView message handlersvoid CExperiment_Frame_OneView::DrawGrid(CDC *pDC){CRect ClientRect;GetClientRect( &ClientRect );CPen *pNewPen = new CPen;pNewPen->CreatePen(PS_DOT, 1, RGB(256,0,0));CPen *pOldPen = pDC->SelectObject(pNewPen);int x0 = ClientRect.left + m_iMarginSize;int x1 = x0 + (ClientRect.right -ClientRect.left - 2*m_iMarginSize)/m_iPointSize * m_iPointSize;int y0 = ClientRect.bottom - m_iMarginSize;int y1 = y0 - (ClientRect.bottom - ClientRect.top - 2*m_iMarginSize)/m_iPointSize * m_iPointSize;int x, y;//Draw horizontal linesfor ( y = y0; y >= y1; y -= m_iPointSize){pDC->MoveTo(x0, y);pDC->LineT o(x1, y);}//Draw vertical linesfor ( x = x0; x <= x1; x += m_iPointSize){pDC->MoveTo(x, y0);pDC->LineT o(x, y1);}pDC->SelectObject(pOldPen);pNewPen->DeleteObject();return;}void CExperiment_Frame_OneView::DrawPixel(int X, int Y) {CDC *pDC= GetDC();CBrush *pNewBrush = new CBrush;pNewBrush->CreateSolidBrush(m_PointColor);CBrush *pOldBrush = pDC->SelectObject(pNewBrush); CPen *pNewPen = new CPen;pNewPen->CreatePen(PS_NULL, 1, RGB(0,0,0));CPen *pOldPen = pDC->SelectObject(pNewPen); CRect ClientRect;GetClientRect( &ClientRect );int x0 = ClientRect.left + m_iMarginSize;int y0 = ClientRect.bottom - m_iMarginSize;CRect Point;Point.left = x0 + X*m_iPointSize;Point.right = Point.left + m_iPointSize;Point.bottom = y0 - Y*m_iPointSize;Point.top = Point.bottom - m_iPointSize;pDC->Rectangle(&Point);pDC->SelectObject(pOldBrush);pNewBrush->DeleteObject();pDC->SelectObject(pOldPen);pOldPen->DeleteObject();}void CExperiment_Frame_OneView::OnSetting(){CSettingDlg SettingDialog(m_iPointSize,m_PointColor,m_iActive_Algorithm,m_bGridOn);if ( SettingDialog.DoModal() == IDOK ){this->m_bGridOn = SettingDialog.m_bGridOn;this->m_PointColor = SettingDialog.m_Point_Color;this->m_iPointSize = SettingDialog.m_Point_Size;this->m_iActive_Algorithm = SettingDialog.m_iActive_Algorithm;this->Invalidate();}}void CExperiment_Frame_OneView::OnInput(){CInputDialog InputDialog(X0, Y0, X1, Y1);if ( InputDialog.DoModal() == IDOK){X0 = InputDialog.m_X0;X1 = InputDialog.m_X1;Y0 = InputDialog.m_Y0;Y1 = InputDialog.m_Y1;Invalidate();}}//-------------------------算法实现------------------------------////绘制像素的函数DrawPixel(x, y);void CExperiment_Frame_OneView::DDA(int X0, int Y0, int X1, int Y1){int dx,dy,epsl,k;float x,y,xIncre,yIncre;dx=X1-X0; dy=Y1-Y0;x=X0; y=Y0;if(abs(dx)>abs(dy)) epsl=abs(dx);else epsl=abs(dy);xIncre=(float)dx/(float)epsl;yIncre=(float)dy/(float)epsl;for(k=0;k<=epsl;k++){DrawPixel (int(x+0.5),(int)(y+0.5));x+=xIncre;y+=yIncre;}}void CExperiment_Frame_OneView::Mid_Bresenham(int X0, int Y0, int X1, int Y1) {int dx,dy,d,UpIncre,DownIncre,x,y;if(X0>X1){x=X1;X1=X0;X0=x;y=Y1;Y1=Y0;Y0=y;}x=X0;y=Y0;dx=X1-X0; dy=Y1-Y0;d=dx-2*dy; UpIncre=2*dx-2*dy; DownIncre=-2*dy; while(x<=X1){DrawPixel(x,y);x++;if(d<0){y++;d+=UpIncre;}else d+=DownIncre; }}。
计算机图形学 算法总结

外侧的不算交点。
Байду номын сангаас
五、 消隐
画家算法 对场景中的多边形按深度进行排序,形成深度优先级表, 按从远倒近的顺序 显示多边形 不能处理循环遮挡,计算量大。 Z 缓冲器算法 { for(v=0;v<vmax;v++) for(u<0;u<umax;u++) { 置 Z 缓冲器的第(u,v)单元的深度值为-1 置帧缓冲器的第(u,v)单元的颜色值为背景色 } for(每一个多边形) for(多边形投影区域内的每一个像素) { 计算多边形在当前像素(u,v)处的深度值,记为 d; if(d>Z 缓冲器的(u,v)单元的值) { 置 Z 缓冲器的第(u,v)单元的深度值为 d; 置帧缓冲器的第(u,v)单元的颜色值为当前多边形颜色值; } } 扫描线 Z 缓冲器算法
加权区域采样方法 改进非加权区域采样方法:相交面积相同,像素亮度可能不同 求出相交区域 A’,然后用 计算相交区域对像素的亮度贡献值,这个计
算结果乘以最大亮度值就是该像素的亮度。W(x,y)是高斯分布函数。 离散算法: 分割像素成 n 个子像素,每个子像素面积为 1/n,用 计算每个子像素
对原像素的亮度贡献权值, 记录在加权表中。然后求所有中心落在直线段里的子 像素的集合。最后针对上述集合计算亮度贡献权值的代数和作为亮度值。
扫描转换多边形 逐点判断法、扫描线算法、边缘填充法 逐点判断法: 射线法:从每个象素点发射线,交点个数偶数的在外,反之在内。避免射线 通过顶点。 累积角度法: 记录从该象素到多边形每个顶点的有向角 (逆时针旋转为正) , 若代数和为 0 则在外,若为正负 2pi 的在内。 编码方法:从 X 轴起逆时针把各象限编码,确认各顶点所在象限的编码, 然后两顶点相减计算各边的编码,用 4 处理使编码绝对值不大于 2,最后求各边 编码代数和。代数和为 0 的在外,为正负 4 的在内。特殊情况:(1)点在边上.预 处理解决 (2)代数和为正负 2(取中点再编码,递归) 扫描线算法 求扫描线与多边形各边的交点 对所得交点从小到大排序 两两配对,填充每个区段 原则:与扫描线的交点向多边形内取整。交点落在象素点上时,仅落在左边上的 属于多边形。交点为多边形顶点时,每个边被认为下闭上开(p74)。 数据结构和算法流程 P76 特点:算法效率比逐点填充法高很多 缺点:对各种表的维持和排序开销太大,适合软件实现而不是硬件实现。
计算机图形学 自行车 旋转平移 等代码

glutAddMenuEntry("实体正四面体",2);
glutAddMenuEntry("线框正八面体",3);
glutAddMenuEntry("实体正八面体",4);
int nGlutCurveMenu = glutCreateMenu(ProcessMenu); //创建GLUT曲面绘制菜单
setbkcolor(6);
/*画前轮*/
circle(x/2,y/2,30);
for(k=0;k<=360;k+=30){
line( x/2,y/2,x/2+30*cos((x/2+k)*0.01745),y/2+30*sin((x/2+k)*0.01745));}
/*画后轮*/
circle(x/2+100,y/2,30);
registerbgidriver(EGAVGA_driver);/*注册BGI驱动后可以不需要.BGI文件的支持运行*/
initgraph(&gd, &gm, "");
}
int main(void)
{ void *w1,*w2;
int i,k;
int x=500,y=300;
initgr(); /* BGI初始化*/
circle(x/2+20,y/2-90,4);
line(x/2+70,y/2-60,x/2+90,y/2-60);
w1=malloc(imagesize(x/2-130,y/2-90,x/2+130,y/2+30));
计算机图形学各种算法

计算机图形学已成为计算机技术中发展最快的领域,计算机图形软件也相应得到快速发展。
计算机绘图显示有屏幕显示、打印机打印图样和绘图机输出图样等方式,其中用屏幕显示图样是计算机绘图的重要内容。
计算机上常见的显示器为光栅图形显示器,光栅图形显示器可以看作像素的矩阵。
像素是组成图形的基本元素,一般称为“点”。
通过点亮一些像素,灭掉另一些像素,即在屏幕上产生图形。
在光栅显示器上显示任何一种图形必须在显示器的相应像素点上画上所需颜色,即具有一种或多种颜色的像素集合构成图形。
确定最佳接近图形的像素集合,并用指定属性写像素的过程称为图形的扫描转换或光栅化。
对于一维图形,在不考虑线宽时,用一个像素宽的直、曲线来显示图形。
二维图形的光栅化必须确定区域对应的像素集,并用指定的属性或图案进行显示,即区域填充。
复杂的图形系统,都是由一些最基本的图形元素组成的。
利用计算机编制图形软件时,编制基本图形元素是相当重要的,也是必需的。
点是基本图形,本章主要讲述如何在指定的输出设备(如光栅图形显示器)上利用点构造其他基本二维几何图形(如点、直线、圆、椭圆、多边形域及字符串等)的算法与原理,并利用Visual C++编程实现这些算法。
1.1 直线数学上,理想的直线是由无数个点构成的集合,没有宽度。
计算机绘制直线是在显示器所给定的有限个像素组成的矩阵中,确定最佳逼近该直线的一组像素,并且按扫描线顺序,对这些像素进行写操作,实现显示器绘制直线,即通常所说的直线的扫描转换,或称直线光栅化。
由于一图形中可能包含成千上万条直线,所以要求绘制直线的算法应尽可能地快。
本节介绍一个像素宽直线的常用算法:数值微分法(DDA)、中点画线法、Bresenham 算法。
计算机图形学原理及算法教程 (Visual C++版) 21.1.1 DDA (数值微分)算法DDA 算法原理:如图1-1所示,已知过端点000111(, ), (, )p x y p x y 的直线段01p p ;直线斜率为1010y y k x x -=-,从x 的左端点0x 开始,向x 右端点步进画线,步长=1(个像素),计算相应的y 坐标y k x B =+;取像素点 [x , round (y )] 作为当前点的坐标。
计算机图形学直线曲线和圆等等算法代码及截图

计算机图形学期中作业姓名:学号:专业:计算机科学与技术班级:2班基本算法:#include <graphics.h>#include<stdio.h>#include <conio.h>#include<math.h>#define ROUND(a) ((int)(a+0.5))void lineDDA (int x1, int y1, int x2, int y2,int color) //DDA 画直线 int ROUND(float a) {return (int)(a+0.5);} {int i;float x,y,k;k=(float)(y2-y1)/(x2-x1);x=(float)x1, y=(float)y1;if (k<=1)for (i=x1 ; i<=x2 ; i++){ putpixel (ROUND(x), ROUND(y),color);x=x+1;y=y+k;}elsefor (i=y1;i<=y2;i++){ putpixel (ROUND(x), ROUND(y),color);x=x+1/k;y=y+1;}void lineBre(int xs, int ys, int xe, int ye,int color) //Bresenham画直线{ int x,y, k, steps;float m, e;m=(float)(ye-ys)/(xe-xs);e=m-0.5;steps=xe-xs;x=xs;y=ys;for (k=0; k<steps; k++){putpixel(x,y,color);if(e>=0){y=y+1;e= e-1;}x=x+1;e=e+m;}void Bs_Mid_Line(int x1,int y1,int x2,int y2,int color) //笔刷画直线{int i,j; int x,y;int a,b; a=y1-y2;b=x2-x1;int cy=(a<=0 ? 1:(a=-a,-1));int cx=(b>=0 ? 1:(b=-b,-1));x=x1; y=y1; for(i=-2; i<=2;i++)for(j=-2; j<=2;j++)putpixel(x,y,color);int d,d1,d2;if(-a<=b) //直线斜率绝对值小于等于1{ d=2*a+b;d1=2*a;d2=2*(a+b);while(x!=x2){if(d<0){x+=cx;y+=cy;d+=d2;}else{x+=cx;d+=d1;}for(i=-2; i<=2;i++)for(j=-2; j<=2;j++)putpixel(x+i,y+j,color);}}else //直线斜率绝对值大于1{ d=2*b+a;d1=2*b;d2=2*(a+b);while(y!=y2){ if(d<0){y+=cy;d+=d1;}else{x+=cx;y+=cy;d+=d2;}for(i=-2; i<=2;i++)for(j=-2; j<=2;j++)putpixel(x+i,y+j,color);}}}void line (int x1,int y1,int x2,int y2,int color)//驻点比较画直线{int x,y,n;int f;n=(x2-x1)+(y2-y1);x=x1;y=y1;f=y*x2-y2+x;for (int i=1; i<=n; i++){ putpixel(x,y,color);if (f>=0){x=x+1;y=y;}else{x=x;y=y+1;}f=y*x2-y2*x;}}void circleMidpoint (int xc, int yc, int r)//中点画圆法{int x=0;int y=r;int p=1-r;void circleplotpoints(int, int, int, int);circleplotpoints(xc, yc, x,y);while(x<y){x++;if ( p<0)p+=2*x+1;else{y--;p+=2*(x-y)+1;}circleplotpoints(xc, yc, x,y);}}void circleplotpoints (int xc, int yc, int x, int y){putpixel(xc+x, yc+y,YELLOW);putpixel(xc-x, yc+y,YELLOW);putpixel(xc+x, yc-y,YELLOW);putpixel(xc-x, yc-y,YELLOW);putpixel(xc+y, yc+x,YELLOW);putpixel(xc-y, yc+x,YELLOW);putpixel(xc+y, yc-x,YELLOW);putpixel(xc-y, yc-x,YELLOW);}arc(int xc, int yc, double r, double ts, double te) //数值微分法产生园弧(DDA算法){ double rad, tsl ,tel, deg, dte,ta, ct,st;int x,y,n,i;rad=0.0174533;tsl=ts*rad;tel=te*rad;if (r<5.08)deg=0.015;else if (r<7.62)deg=0.06;else if (r<25.4)deg=0.075;elsedeg=0.15;dte=deg*25.4/r;if (tel<tsl)tel=tel+6.28319;n=(int)((tel-tsl)/dte+0.5);if (n==0)n=(int)(6.28319/dte+0.5);ta=tsl;x=xc+r*cos(tsl);y=yc+r*sin(tsl);moveto (x,y);for ( i=1; i<=n; i++){ta=ta+dte;ct=cos(ta);st=sin(ta);x=xc+r*ct;y=yc+r*st;lineto (x,y);}x=xc+r*cos(tel);y=yc+r*sin(tel);lineto (x,y);return (0);}void circleBre(int r) //Bresenham画园算法{ int x=0, y=r, d=3-2*r;while (x<y){putpixel (x,y,RED);if (d<0)d=d+4*x+6;else{d=d+4*(x-y)+10;y=y-1;}x=x+1;}if (x==y)putpixel(x,y,RED);}ellipse (int xc, int yc, double a, double b, double alp, double ts, double te) //角度DDA法产生椭圆弧{double rad, tsl, tel, alpl, deg, dte, r, ta, a1,a2,b1,b2; int x,y,n,i;rad=0.0174533;tsl=ts*rad;tel=te*rad;alpl=alp*rad;a1=a*cos(tsl);b1=cos(alpl);a2=b*sin(tsl);b2=sin(alpl);r=(a>b)?a:b;if (r<5.08)deg=0.015;else if (r>7.62)deg=0.06;else if (r<25.4)deg=0.075;elsedeg=0.15;dte=deg*25.4/r;if (tel<tsl)tel+=6.28319;n=(int)(6.28319/dte+0.5); ta=tsl;x=xc+a1*b1-a2*b2;y=yc+a1*b2+a2*b1;moveto (x,y);for (i=1;i<=n;i++){ta+=dte;a1=a*cos(ta);a2=b*sin(ta);x=xc+a1*b1-a2*b2;y=yc+a1*b2+a2*b1;lineto (x,y);}a1=a*cos(tel);a2=b*sin(tel);x=xc+a1*b1-a2*b2;y=(int)yc+a1*b2+a2*b1;lineto (x,y);return(0);}void ellipse (int x0, int y0, int a, int b, int dt) {int x,y,n,i;float t1, t=0.0;t1=(float)dt*0.0174533;n=360/dt;moveto (x0+a, y0);for (i=1;i<n; i++){t=t+t1;x=(int)x0+a*cos(t);y=(int)y0+b*sin(t);lineto (x,y);}lineto (x0+a, y0);}Par(int xs, int ys, int xm, int ym, int xe, int ye) //二次曲线的参数拟合法{double d, d1, ax, ay, bx,by;int n,i;ax=(xe-2*xm+xs)*2.0;ay=(ye-2*ym+ys)*2.0;bx=(xe-xs-ax);by=(ye-ys-ay);n=(int)sqrt(ax*ax+ay*ay)/4;n=(int)sqrt(n*100);moveto (xs,ys);d=1.0/n;d1=d;for (i=0; i<=n;i++){ lineto ((int)( ax*d1*d1+bx*d1+xs), (int) (ay*d1*d1+by*d1+ys));d1=d1+d;}lineto (xe, ye);return (0);}void main(){printf("1: DDA画直线.\n");printf("2: Bresenham 画直线.\n");printf("3: 笔刷画直线.\n");printf("4: 驻点比较画直线.\n");printf("5: 中点画圆法.\n");printf("6: 数值微分法产生园弧(DDA算法).\n");printf("7: Bresenham画园算法.\n");printf("8: 角度DDA法产生椭圆弧.\n");printf("9: 二次曲线的参数拟合法.\n");printf("0: 退出.\n\n");while(true){printf("请输入你要选择的方法:\n");int a;scanf("%d",&a);switch(a){case 0:exit(0);case 1:initgraph(640, 480);lineDDA(100,100,400,450,YELLOW);break;case 2:initgraph(640, 480);lineBre(100, 100, 450, 500,YELLOW);break;case 3:initgraph(640, 480);Bs_Mid_Line(100,100,450,500,YELLOW);break;case 4:initgraph(640, 480);line (100,100,450,500,YELLOW);break;case 5:initgraph(640, 480);circleMidpoint (100, 100, 50) ;break;case 6:initgraph(640, 480);arc(200, 200, 100, 30, 90);break;case 7:initgraph(640, 480);circleBre(100);break;case 8:initgraph(640, 480);ellipse (100, 100, 50, 60, 20, 30, 90) ; break;case 9:initgraph(640, 480);Par(100, 100, 300, 350, 50, 100);break;case 10:default :printf("错误\n");}getch();cleardevice();closegraph();}}程序运行截图如下:。
计算机图形学各种算法

1.线面遮挡算法1)视点和线段在给定平面的同侧,线段不被给定平面遮挡。
2)线段的投影和平面的投影的包围盒不相交,线段不被平面遮挡。
3)计算直线与平面是否相交。
若无相交转4);否则交点在线段的内部或外部。
若交点在线段内部,交点将线段分为两段,与视点同侧的一段不被遮挡,另一段在视点异侧,转4);若交点在线段外部,转4)。
4)求所剩线段的投影和平面边界的投影的所有交点,根据交点在原直线参数方程中的参数值求出Z值。
若无交点,转4)。
5)所求的各交点将线段的投影分为若干段,求出第一段中点。
6)若第一段中点在平面的投影内,则相应的段被遮挡,否则不被遮挡,其他段依次交替取值进行判断。
7)算法结束。
2.深度排序算法1)把所有的多边形按顶点最大z坐标值进行排序。
2)解决当多边形在z坐标范围内发生交迭时出现的不明确问题。
3)按最大z坐标值逐次减小的次序,对每个多边形进行扫描转换。
3.Z-缓冲算法:更新缓冲区置成背景色;Z-缓冲区置成最大z值;For(各个多边形){扫描转换该多边形;For(计算多边形所覆盖的每个像素(x,y)){计算多边形在该像素的深度值z(x,y);If(z(x,y)小于z缓冲区中的(x,y)处的值){把z(x,y)存入z缓冲区中的(x,y)处;把多边形在(x,y)处的颜色值存入更新缓存区的(x,y)处;}}}4.Z—缓冲算法的改进,只用一个缓冲存储器实现消隐Z-Buffer(){帧缓存全置为背景色;For(屏幕上的每个像素(i,j){深度缓存变量zb置最大值MaxValue;For(多面体上的每个多边形Pk){if(像素点(i,j)在pk的投影多边形之内){计算Pk在(i,j)处的深度值depth;If(depth<zb){zb=depth;indexp=k;}}}If(zb!=MaxV alue)计算多边形pindexp在交点(i,j)处的光照颜色并显示}}4.Graham扫描求凸壳算法V oid Graham(POINT S[],intn){sortangle(S,n,Q);v=first(Q);While(next(v,Q)!=first(Q))If(left(v,next(v,Q),next(next(v,Q),Q)) v=next(v,Q);Else{delete(next(v,Q);v=pred(v,Q);}}5.jarvis行进V oid Javis(POINT S[],int n){v0=xy_minsort(S,n);d=(0,-1);Q=null;add(Q,v0);S1=delete(v0,S);u=v0;V1=wapping(u,d,S1);While(v1!=v0){add(v1,Q);S1=delete(v1,S);S1=delete(u,S1);D=vector(u,v1);u=v1;v1=wapping(u,d,S1);}}6.简单多边形三角剖分V oidSimple_polygon_triangulation(POINT *P,int n){Q0=P,m=n;While(m<3){Q1=next(Q0);Q2=next(Q1);If(Test(Q0,Q1,Q2){输出三角形Q0Q1Q2;m--;delete(Q1);}Else Q0=Q1;}输出Q0开始的剩下的三角形;}7.凸多边形包含算法Int inner1(POINT p[],intn,POINT q){int i,j,k; i=1;j=n-1;While(j-i>1){k=(i+j)/2;If(test(q,p,0,k)==0) return1;else(test(q,p,0,k)==1) return0;else(test(q,p,0,k)==2) i=k;else(test(q,p,0,k)==3) j=k;if(test3(q,p,0,i,j)) return 1;Else return 0;}8.凸多边形重叠计算V oid advance(POINT P[],intl,POINT Q[];int m){int s; s=vector3(P,Q,i,j);If(s>=0){If((left(P,i,Q,j)&&left(Q,j,P,i))||(right(P,i,Q,j)&&left(Q,j,P,i))){if(i<1) ++i;else i=1;}Else if(j<m) j++;else j=1;}Elseelse{p+=2*dy;}}} If((right(P,i,Q,j)&&left(Q,j,P,i))||(right(P,i,Q,j)&&right(Q,j,P,i))){if(i<1) ++i;else i=1;}Else if(j<m) j++;else j=1;}}9.DDAV oid DDALine(int x1,inty1,int x2,int y2){ double dx,dy,e,x,y;dx=x2-x1;dy=y2-y1;e=(fabs(dx)>fabs(dy))?fabs(dx):fabs(dy);dx/=e;dy/=e;x=x1;y=y1;for(int i=0;i<=e;i++){SetPixel((int)(x+0.5),(int)(y+0.5),color);x+=dy;y+=dy;}}10.中点划线MidpointLine(int x0,int y0,int x1,int y1){int a,b,delta1,delta2,d,x,y;a=y0-y1;b=x1-x0;d=2*a+b;delta1=2*a;delta2=2*(a+b);x=x0;y=y0;SetPixel(x,y,color);while(x<x1){If(d<0){x++;y++;d+=delta2;}else{x++;d+=delta1;}SetPixel(x,y,color);}}11.BresenhamLinevoid B(int x1,int y1,int x2,inty2){int x,y,dx,dy,p;x=x1;y=y1;dx=x2-x1;dy=y2-y1;P=2*dy-dx;for(;x<=x2;x++){SetPixel(x,y,color);If(p>=0){y++;p+=2*(dy-dx);}。
计算机图形学代码

像素函数56. putpixel() 画像素点函数57. getpixel()返回像素色函数直线和线型函数58. line() 画线函数59. lineto() 画线函数60. linerel() 相对画线函数61. setlinestyle() 设置线型函数62. getlinesettings() 获取线型设置函数63. setwritemode() 设置画线模式函数多边形函数64. rectangle()画矩形函数65. bar() 画条函数66. bar3d() 画条块函数67. drawpoly() 画多边形函数圆、弧和曲线函数68. getaspectratio()获取纵横比函数69. circle()画圆函数70. arc() 画圆弧函数71. ellipse()画椭圆弧函数72. fillellipse() 画椭圆区函数73. pieslice() 画扇区函数74. sector() 画椭圆扇区函数75. getarccoords()获取圆弧坐标函数填充函数76. setfillstyle() 设置填充图样和颜色函数77. setfillpattern() 设置用户图样函数78. floodfill() 填充闭域函数79. fillpoly() 填充多边形函数80. getfillsettings() 获取填充设置函数81. getfillpattern() 获取用户图样设置函数图像函数82. imagesize() 图像存储大小函数83. getimage() 保存图像函数84. putimage() 输出图像函数图形和图像函数对许多图形应用程序,直线和曲线是非常有用的。
但对有些图形只能靠操作单个像素才能画出。
当然如果没有画像素的功能,就无法操作直线和曲线的函数。
而且通过大规模使用像素功能,整个图形就可以保存、写、擦除和与屏幕上的原有图形进行叠加。
编辑本段(一) 像素函数putpixel() 画像素点函数功能:函数putpixel() 在图形模式下屏幕上画一个像素点。
计算机图形学部分代码

一、使用MFC AppWizard(exe)生成直线应用程序的框架画直线:(下面红色部分是我们要添加的代码)详见课本P75-76页法一、中点画直线法(1)主代码:void MPline(int x1,int y1,int x2,int y2,int color,CDC* pDC){int x,y,a,b,d,d1,d2;a=y2-y1;b=x2-x1;y=y1;d=2*a+b;d1=2*a;d2=2*(a+b);pDC->SetPixel(x,y,color);for(x=x1;x<=x2;x++){if(d<0){y++;d+=d2;}else{d+=d1;}pDC->SetPixel(x,y,color);// for (i=-2;i<=2;i++) //详见课本P126页// for (j=-2;j<=2;j++)// pDC->SetPixel(x+i,y+j,color);}}void CLineView::OnDraw(CDC* pDC){CLineDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);int i,j,x1=450,y1=300,x2=1000,y2=300,color=RGB(255,128,0);MPline(x1, y1, x2,y2,color,pDC);(2)代码运行图:法二、Bresenham算法绘制直线(1)、主要代码void BHline(int x1,int y1,int x2,int y2,int color,CDC* pDC) {int x,y,dx,dy,dk;dx=x2-x1;dy=y2-y1;dk=2*dy-dx;y=y1;for(x=x1;x<=x2;x++){pDC->SetPixel(x,y,color); // for (i=-2;i<=2;i++)// for (j=-2;j<=2;j++)// pDC->SetPixel(x+i,y+j,color);dk=dk+2*dy;if(dk>=0){y++;dk=dk-2*dx;}}}void CLineView::OnDraw(CDC* pDC){CLineDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);int i,j,x1=300,y1=100,x2=1000,y2=300,color=RGB(0,175,255);BHline(x1, y1, x2,y2+500,color,pDC);(2)代码运行图:法三、数值微分法DDALine()算法画直线(1)主要代码void DDLine(int x1,int y1,int x2, int y2,int color,CDC *pDC){int x;float k,y=y1;k=(y2-y1)/(x2-x1);for(x=x1;x<=x2;x++){pDC->SetPixel(x,int(y+0.5),color); // for (i=-2;i<=2;i++)// for (j=-2;j<=2;j++)// pDC->SetPixel(x,int(y+0.5),color);y=y+k;}}void CLineView::OnDraw(CDC* pDC){CLineDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);int i,j,x1=450,y1=300,x2=1000,y2=300,color=RGB(0,0,255);DDLine(x1,y1,x2, y2,color,pDC);(2)代码运行图二、使用MFC AppWizard(exe)生成直线应用程序的框架画直线:法一:中点画圆法(其中红色部分是我们要添加的的代码)void MidpointCircle(CDC *pdc,int x0,int y0,int r,int color){int x,y;float d;x=0;y=r;d=1.25-r;pdc->SetPixel(x0+x,y0-y,color);while(x<=y){x++;if(d<0){d+=2*x+3;}else{y--;d+=2*(x-y)+5;}pdc->SetPixel(x0+x,y0-y,color); pdc->SetPixel(x0-x,y0-y,color);pdc->SetPixel(x0+x,y0+y,color); pdc->SetPixel(x0-x,y0+y,color);pdc->SetPixel(x0+y,y0-x,color); pdc->SetPixel(x0-y,y0-x,color);pdc->SetPixel(x0+y,y0+x,color); pdc->SetPixel(x0-y,y0+x,color);}}void CCilView::OnDraw(CDC* pDC){CCilDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);int x0,y0;x0=138,y0=138;int r=100;int color=RGB(255,0,255);CClientDC dc(this);MidpointCircle(&dc,x0,y0,r,color);// TODO: add draw code for native data here}法二、Bresenham画圆法(缺货中······)void BresenhamCircle(int R,CDC *pDC){int x0,y0,x,y,p;x0=200;y0=200;x = x0;y=y0 + R;p=3-2*R;for(;x<=y;x++){pDC->SetPixel(x,y,RGB(255,0,0));pDC->SetPixel(x,2*y0-y,RGB(255,0,0)); pDC->SetPixel(y,x,RGB(255,0,0));pDC->SetPixel(2*y0-y,x,RGB(255,0,0)); pDC->SetPixel(2*x0-x,y,RGB(255,0,0)); pDC->SetPixel(y,2*x0-x,RGB(255,0,0)); pDC->SetPixel(2*x0-x,2*y0-y,RGB(255,0,0)); pDC->SetPixel(2*y0-y,2*x0-x,RGB(255,0,0)); if(p>=0){p+=4*(x-y)+10;y--;}else{p+=4*(x-x0)+6;}}}void CCilView::OnDraw(CDC* pDC){CCilDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data here BresenhamCircle(50,pDC);}。
计算机图形学

2.2 圆的生成算法 2.2.3 中点圆生成算法 定义圆函数:f(x,y)=x2+y2-r2 x2+y2-r2=0 yk-1 yk yk+1
两候选象素中点
<0,(x,y)位于圆周边界内 =0,(x,y)位于圆周边界上 >0, (x,y)位于圆周边界外
候选高象素 若Pk<0,则 yk+1取 yk+1=yk, 否则yk+1取 候选低象素 yk-1。
2.2 圆的生成算法 Bresenham圆周生成算法思想如下: ⒈ 求误差初值,p1=3−2r,i=1,画点(0, r); ⒉ 求下一个光栅位置,其中xi+1=xi+1,如果pi<0则 yi+1=yi,否则yi+1=yi−1; ⒊ 画点(xi+1, yi+1); ⒋ 计算下一个误差,如果pi<0则pi+1=pi+4xi+6,否则 pi+1=pi+4(xi−yi)+10; ⒌ i=i+1,如果x=y则结束,否则返回步骤2。
2 2 pk +1 = pk + 2( xk + 1) + ( yk +1 − yk ) − ( yk +1 − yk ) + 1
5 1 p0 = f (1, r − ) = − r 4 2
⎧ pk + 2 xk +1 + 1 − 2 yk +1 , pk ≥ 0 pk +1 = ⎨ , pk < 0 ⎩ pk + 2 xk +1 + 1
2.1 直线的生成算法
2.1 直线的生成算法
|dx|>|dy|? true false true false true false true false
计算机图形学简单画图代码

计算机图形学简单画图代码软件:NetBeans 图形效果:代码:package newpackage;import java.awt.*;import javax.swing.*;import java.awt.geom.*;import java.awt.image.*;import .URL;import java.io.*;import javax.imageio.*;import java.awt.event.*;import java.util.Calendar;import javax.swing.*;public class Hello2D extends JApplet { public static void main(String s[]) { JFrame frame = new JFrame();frame.setTitle("计算机图形学");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);JApplet applet = new Hello2D();applet.init();frame.getContentPane().add(applet);frame.pack();frame.setVisible(true);}public void init() {JPanel panel = new Hello2DPanel();getContentPane().add(panel);}}class Hello2DPanel extends JPanel implements ActionListener{ private BufferedImage image;AffineTransform rotH = new AffineTransform();AffineTransform rotM = new AffineTransform();AffineTransform rotS = new AffineTransform();// AffineTransform zuq=new AffineTransform ();public Hello2DPanel() {setPreferredSize(new Dimension(1400,1000));setBackground(Color.white);Timer timer=new Timer(500,this);timer.start();URLurl=getClass().getClassLoader().getResource("images/zuqiu.jpg" );try{image=ImageIO.read(url);}catch(IOException ex){ex.printStackTrace();}}@Overridepublic void paintComponent(Graphics g) {super.paintComponent(g);Graphics2D g2= (Graphics2D)g;g2.translate(100,100);g2.scale(0.5, 0.5);for (int i = 0; i < 12; i++) {g2.rotate(2*Math.PI/12);g2.fill3DRect(-3, -180, 6, 30, true);}Shape hour = new Line2D.Double(0, 0, 0, -80);hour = rotH.createTransformedShape(hour);Shape minute = new Line2D.Double(0, 0, 0, -120);minute = rotM.createTransformedShape(minute);Shape second = new Line2D.Double(0, 0, 0, -120);second = rotS.createTransformedShape(second);g2.setColor(Color.black);g2.setStroke(new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.draw(hour);g2.draw(minute);g2.setStroke(new BasicStroke(2));g2.draw(second);g2.scale(2,2);g2.translate(50,-150);g2.setColor(Color.DARK_GRAY);GeneralPath path=new GeneralPath();path.moveT o(200, 170);path.lineT o(800, 170);path.quadTo(950, 350, 800,530 );path.lineT o(200, 530);path.quadTo(50, 350, 200,170);Stroke stroke=new BasicStroke(4,BasicStroke.CAP_BUTT,BasicStroke.CAP_ROUND);//设置笔画g2.setStroke(stroke);g2.translate(-100, -100);//平移g2.scale(1.4,1.4 );//放大path.closePath();g2.draw(path);g2.setColor(Color.LIGHT_GRAY);g2.fill(path);Shape s1=new Rectangle2D.Double(300,250, 400, 200);Shape s2=new Ellipse2D.Double(200,250, 200, 200);Shape s3=new Ellipse2D.Double(600,250, 200, 200);g2.setColor(Color.DARK_GRAY);g2.draw(s1);g2.draw(s2);g2.draw(s3);g2.setColor(Color.GREEN);Area a1=new Area(s1);Area a2=new Area(s2);a1.add(a2);g2.fill(a1);Area a3=new Area(s3);a1.add(a3);g2.fill(s3);Font font=new Font("Serif",Font.BOLD,25);g2.setFont(font);GradientPaint gp=new GradientPaint(450,200,Color.red,220,220,Color.BLACK,true);g2.setPaint(gp);g2.drawString("四百米跑道",450, 220);g2.setColor(Color.BLACK);Stroke stroke1=new BasicStroke(1);//设置笔画g2.setStroke(stroke1);Shape s4=new Rectangle2D.Double(300,250, 400, 200);g2.draw(s4);g2.drawLine(500, 250, 500, 450);//划直线g2.drawOval(465, 315, 70, 70);g2.drawLine(300, 300, 350, 300);g2.drawLine(350, 300, 350,400);g2.drawLine(350, 400, 300,400);g2.drawLine(300, 325, 325, 325);g2.drawLine(325, 325, 325,375);g2.drawLine(325, 375, 300,375);g2.drawLine(700, 300, 650,300);g2.drawLine(650, 300, 650, 400);g2.drawLine(650, 400, 700,400);g2.drawLine(700, 325, 675,325);g2.drawLine(675, 325, 675, 375);g2.drawLine(675,375, 700,375);//绘制虚线float[] dashArray={20,20,20,20};g2.setColor(Color.BLACK);Font font2=new Font("Serif",Font.BOLD,15);g2.setFont(font2);g2.drawString("1",290,465);g2.drawString("2",290,485);g2.drawString("3",290,505);g2.drawString("4",290,525);g2.drawLine(300, 450,300 ,530);g2.setColor(Color.red);g2.drawLine(700, 450,700 ,530);float dashPhase=50;stroke =newBasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL ,0,dashArray,dashPhase);g2.setStroke(stroke);g2.drawLine(300, 470,700 ,470);g2.drawLine(300, 490,700 ,490);g2.drawLine(300, 510,700 ,510);Font font1=new Font("Serif",Font.BOLD,15);g2.setFont(font1);GradientPaint gp1=new GradientPaint(450,200,Color.BLACK,220,220,Color.red);g2.setPaint(gp1);g2.drawString("200米接力赛跑道",400,480);TexturePaint tp=new TexturePaint(image,new Rectangle2D.Double(550,370,image.getWidth(),image.getHeight ()));g2.setPaint(tp);Shape zq=new Rectangle.Double(550,370,90,50);// zq=zuq.createTransformedShape(zq);g2.fill(zq);}@Overridepublic void actionPerformed(ActionEvent e) {int hour = Calendar.getInstance().get(Calendar.HOUR); int min = Calendar.getInstance().get(Calendar.MINUTE); int sec = Calendar.getInstance().get(Calendar.SECOND); rotH.setToRotation(Math.PI * (hour+min/60.0)/6.0); rotM.setToRotation(Math.PI * min /30.0);rotS.setToRotation(Math.PI * sec /30.0);repaint();}}。
计算机图形学第3章

第3章 基本图形生成算法
3.1 生成直线的常用算法
均假定所画直线的斜率k∈[0,1]。
3.1.1 DDA画线算法
DDA(Digital Differential Analyzer)画线 算法也称数值微分法,是一种增量算法。它的算 法实质是用数值方法解微分方程,通过同时对x和 y各增加一个小增量,计算下一步的x、y值。
边界表示的四连通区域种子填充算法 内点表示的四连通区域种子填充算法 边界表示的八连通区域种子填充算法 内点表示的八连通区域种子填充算法
第3章 基本图形生成算法
1.边界表示的四连通区域种子填充算法
基本思想:从多边形内部任一点(像素)出发,依“左 上右下”顺序判断相邻像素,若其不是边界像素且没有被填 充过,对其填充,并重复上述过程,直到所有像素填充完毕。 可以使用栈结构来实现该算法,算法的执行步骤如下: 种子像素入栈,当栈非空时,重复执行如下三步操作: (1)栈顶像素出栈; (2)将出栈像素置成多边形填充的颜色; (3)按左、上、右、下的顺序检查与出栈像素相邻的 四个像素,若其中某个像素不在边界上且未置成多边形色, 则把该像素入栈。
过各行各列像素中心构造一组虚拟网格线,按直 线从起点到终点的顺序计算直线与各垂直网格线的交 点,然后确定该列像素中与此交点最近的像素。 由图3-5不难看出:若s<t, 则Si比较靠近理想直线,应 选Si;若s≥t,则Ti比较靠近 理想直线,应选Ti。
第3章 基本图形生成算法
令dx=x2-x1,dy=y2-y1 递推公式 :di 1 di 2dy 2dx( yi yi 1 ) di的初值: d1 2dy dx 当di≥0时,选Ti,
第3章 基本图形生成算法
计算机图形学_有效边表算法源代码

#include <stdio.h>#include <malloc.h>#include <gl/glut.h>#include <Windows.h>#define EPSILON 0.000001 //最小浮点数//点结构体struct Point{int x; //x坐标int y; //y坐标};//线结构体struct Line{Point high_point; //高端点Point low_point; //低端点int is_active; //是否为有效边,水平边(0),非水平边(1)double inverse_k; //斜率k的倒数};//边结点struct EdgeNode{double x; //扫描线与边交点的x坐标(边的低端点的x坐标)int y_max; //边的高端点的y坐标ymaxdouble inverse_k; //斜率k的倒数EdgeNode *next; //下一个边结点的指针};//有效边表struct ActiveEdgeTable{int y; //扫描线yEdgeNode *head; //边链表的头指针};//桶结点typedef struct Bucket{int y; //扫描线yEdgeNode *head; //边链表的头指针Bucket *next; //下一个桶的指针} EdgeTable;int compare(Point p1, Point p2);Line* create_lines(Point points[], int n);Point get_lowest_point(Line lines[], int n);Point get_highest_point(Line lines[], int n);void swap(Line &l1, Line &l2);void sort(Line lines[], int n);EdgeTable* create_edge_table(Line lines[], int n);ActiveEdgeTable* init_active_table(EdgeTable *edge_table);void delete_edge(ActiveEdgeTable *active_table, int y_max);void add_edge(ActiveEdgeTable *active_table, EdgeNode edge);ActiveEdgeTable* update_active_table(ActiveEdgeT able *active_table, EdgeTable *edge_table);void DrawPolygon(Point points, int n);void DrawGrid(int x, int y);void Fill(Point points[], int n);void Initial();void Display();int main(int argc, char* argv[]){glutInit(&argc, argv);glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);glutInitWindowSize(400, 300);glutInitWindowPosition(100, 120);glutCreateWindow("Polygon Filling");glutDisplayFunc(Display);Initial();glutMainLoop();return 0;}//比较2个点的高度int compare(Point p1, Point p2){if (p1.y > p2.y)return 1;else if (p1.y == p2.y)return 0;return -1;}//由点数组生成线段数组Line* create_lines(Point points[], int n){Line *lines = (Line*)malloc(n * sizeof(Line));for (int i = 0; i < n; ++i){Point p1 = points[i];Point p2 = points[(i + 1) % n];int result = compare(p1, p2);if (result == 0)lines[i].is_active = 0;elselines[i].is_active = 1;lines[i].high_point = result > 0 ? p1 : p2;lines[i].low_point = result < 0 ? p1 : p2;lines[i].inverse_k = (double)(p2.x - p1.x) / (double)(p2.y - p1.y);}return lines;}//获取线数组中最低的端点Point get_lowest_point(Line lines[], int n){Point lowest_point = lines[0].low_point;for (int i = 1; i < n; ++i){Point low_point = lines[i].low_point;if (compare(lowest_point, low_point) > 0)lowest_point = low_point;}return lowest_point;}//获取线数组中最高的端点Point get_highest_point(Line lines[], int n){Point highest_point = lines[0].high_point;for (int i = 1; i < n; ++i){Point high_point = lines[i].high_point;if (compare(highest_point, high_point) < 0)highest_point = high_point;}return highest_point;}//交换2个Line对象void swap(Line &l1, Line &l2){Line temp = l1;l1 = l2;l2 = temp;}//对线数组进行排序void sort(Line lines[], int n){//先按低端点的y坐标进行升序排序for (int i = 0; i < n; ++i){int min_index = i;for (int j = i + 1; j < n; ++j){if (lines[j].low_point.y < lines[min_index].low_point.y)min_index = j;}swap(lines[i], lines[min_index]);}//再将有序数组按低端点的x坐标升序排列,若x坐标相等,按inverse_k升序for (i = 0; i < n; ++i){int min_index = i;for (int j = i + 1; lines[j].low_point.y == lines[i].low_point.y; ++j){if (lines[j].low_point.x < lines[min_index].low_point.x)min_index = j;}swap(lines[i], lines[min_index]);if (i > 0 && lines[i].low_point.x == lines[i - 1].low_point.x){if (lines[i].is_active == 1 && lines[i - 1].is_active == 1){if (lines[i].inverse_k < lines[i - 1].inverse_k)swap(lines[i], lines[i - 1]);}}}}//创建一个边表EdgeTable* create_edge_table(Line lines[], int n){EdgeTable *edge_table = (EdgeTable*)malloc(sizeof(EdgeTable));edge_table->head = NULL;edge_table->next = NULL;sort(lines, n);Point lowest_point = get_lowest_point(lines, n);Point highest_point = get_highest_point(lines, n);EdgeTable *s = edge_table;for (int i = lowest_point.y; i <= highest_point.y; ++i){Bucket *bucket = (Bucket*)malloc(sizeof(Bucket));bucket->y = i;bucket->next = NULL;bucket->head = (EdgeNode*)malloc(sizeof(EdgeNode));bucket->head->next = NULL;EdgeNode *p = bucket->head;for (int j = 0; j < n; ++j){if (lines[j].is_active == 0)continue;if (lines[j].low_point.y == i){EdgeNode *q = (EdgeNode*)malloc(sizeof(EdgeNode));q->x = lines[j].low_point.x;q->y_max = lines[j].high_point.y;q->inverse_k = lines[j].inverse_k;q->next = NULL;p->next = q;p = q;}}s->next = bucket;s = bucket;}return edge_table;}//从边表中取出第一个不为空的桶初始化有效边表ActiveEdgeTable* init_active_table(EdgeTable *edge_table){ActiveEdgeTable *active_table = (ActiveEdgeTable*)malloc(sizeof(ActiveEdgeTable));active_table->y = edge_table->next->y;active_table->head = (EdgeNode*)malloc(sizeof(EdgeNode));active_table->head->next = NULL;EdgeNode *p = edge_table->next->head;EdgeNode *q = active_table->head;while (p->next != NULL){EdgeNode *s = (EdgeNode*)malloc(sizeof(EdgeNode));s->x = p->next->x;s->y_max = p->next->y_max;s->inverse_k = p->next->inverse_k;s->next = NULL;q->next = s;q = s;p = p->next;}return active_table;}//从有效边表中删除指定y_max的边结点void delete_edge(ActiveEdgeTable *active_table, int y_max){EdgeNode *p = active_table->head;while (p->next != NULL){EdgeNode *q = p->next;if (q->y_max == y_max){p->next = q->next;free(q);}elsep = p->next;}}//将一个边结点按次序添加到有效边表中void add_edge(ActiveEdgeTable *active_table, EdgeNode edge){EdgeNode *t = (EdgeNode*)malloc(sizeof(EdgeNode));t->x = edge.x;t->y_max = edge.y_max;t->inverse_k = edge.inverse_k;t->next = NULL;EdgeNode *p = active_table->head;while (p->next != NULL){EdgeNode *q = p->next;if ((edge.x < q->x) || (edge.x == q->x && edge.inverse_k < q->inverse_k)){p->next = t;t->next = q;return;}p = p->next;}p->next = t;}//更新有效边表,并与边表中对应的桶合并ActiveEdgeTable* update_active_table(ActiveEdgeT able *active_table, EdgeTable *edge_table) {//更新扫描线y++active_table->y;//删除y=ymax的边delete_edge(active_table, active_table->y);//更新边结点的数据EdgeNode *p = active_table->head->next;while (p != NULL){p->x += p->inverse_k;p = p->next;}//找到边表中对应的桶EdgeTable *q = edge_table;while ((q = q->next) != NULL && q->y != active_table->y);//如果找到,则进行合并if (q != NULL){EdgeNode *s = q->head;while ((s = s->next) != NULL){add_edge(active_table, *s);}}return active_table;}//画出多边形的边框void DrawPolygon(Point points[], int n){glBegin(GL_LINE_LOOP);for (int i = 0; i < n; ++i)glVertex2i(points[i].x, points[i].y);glEnd();}//画出x * y的网格void DrawGrid(int x, int y){glBegin(GL_LINES);//横线for (int i = 0; i <= y; ++i){glVertex2d(0, i);glVertex2d(x, i);}//竖线for (i = 0; i <= x; ++i){glVertex2d(i, 0);glVertex2d(i, y);}glEnd();}//用指定的像素大小填充多边形void Fill(Point points[], int n){Line *lines = create_lines(points, n);EdgeTable *edge_table = create_edge_table(lines, n);ActiveEdgeTable *active_table = init_active_table(edge_table);while (active_table->head->next != NULL){EdgeNode *p = active_table->head;int b = -1;while (p->next != NULL){if (b > 0){int left = p->x;int right = p->next->x;//如果不是局部最低点,则进行边界处理if (!(p->x - p->next->x >= -EPSILON && p->x - p->next->x <= EPSILON)){//处理左边界if (!(p->x - left >= -EPSILON && p->x - left <= EPSILON))left += 1;//处理右边界if (p->next->x - right >= -EPSILON && p->next->x - right <= EPSILON)right -= 1;}for (int i = left; i <= right; ++i){glBegin(GL_POINTS);glVertex2d(i, active_table->y);glEnd();glFlush();Sleep(50);}}p = p->next;b = -b;}active_table = update_active_table(active_table, edge_table);}}//初始化窗口,x和y指定窗口的坐标大小void Initial(){glClearColor(1.0f, 1.0f, 1.0f, 1.0f);glMatrixMode(GL_PROJECTION);gluOrtho2D(0.0, 20.0, 0.0, 15.0);}//窗口的显示回调函数void Display(){//使用当前背景色填充窗口glClear(GL_COLOR_BUFFER_BIT);//使用灰色画出网格线glColor3f(0.75f, 0.75f, 0.75f);DrawGrid(20, 14);glFlush();//多边形的顶点坐标Point points[] = { { 3, 1 },{ 6, 5 },{ 8, 1 },{ 12, 9 },{ 7, 8 },{ 3, 12 },{ 1, 7 } };//计算顶点个数int n = sizeof(points) / sizeof(Point);//使用黑色画出多边形的边框glColor3f(0.0f, 0.0f, 0.0f);DrawPolygon(points, n);glFlush();//指定点大小glPointSize(6.0f);//使用红色填充多边形glColor3f(1.0f, 0.0f, 1.0f);Fill(points, n);glFlush();}。
计算机图形学-实验五 直线和多边形的裁剪

大学实验报告学院:计算机科学与信息学院专业:软件工程班级:102班学号实验组实验时间指导教师成绩实验项目名称实验五直线和多边形的裁剪实验目的掌握直线段的裁剪算法以及多边形的裁剪算法实验要求熟练掌握直线段的裁剪算法以及多边形的裁剪算法的基本原理,并编写测试代码进行实验。
实验原理Cohen-Sutherland直线剪裁算法以区域编码为基础,将窗口及其周围的,8个方向以4 bit的二进制数进行编码。
右图所示的编码方法将窗口及其邻域分为5个区域:⑴域:区域(0000)。
⑵上域:区域(1001, 1000, 1010)。
⑶下域:区域(0101, 0100, 0110)。
⑷左域:区域(1001, 0001, 0101)。
⑸右域:区域(1010, 0010, 0110)。
当线段的两个端点的编码的逻辑“与”非零时,线段为显然不可见的,对某线段的两个端点的区号进行位与运算,可知这两个端点是否同在视区的上、下、左、右;Cohen-Sutherland直线剪裁算法的算法思想是:对于每条线段P1P2分为三种情况处理。
(1)若P1P2完全在窗口,则显示该线段P1P2简称“取”之。
(2)若P1P2明显在窗口外,则丢弃该线段,简称“弃”之。
(3)若线段既不满足“取”的条件,也不满足“弃”的条件,则在交点处把线段分为两段。
其中while (code1 != 0 || code2 != 0) {if ((code1 & code2) != 0) {// 两端点的编码相与不为0,表示直线在窗口外return;}if (code1 != 0) {code = code1;} else {code = code2;}if ((LEFT & code) != 0) {// 直线的端点与矩形窗口的左边编码相与!=0 x = XL;y = y1 + (y2 - y1) * (XL - x1) / (x2 - x1);// 求直线与矩形窗口的左边界的交点} else if ((RIGHT & code) != 0) {// 直线的端点与矩形窗口的右边编码相与!=0x = XR;y = y1 + (y2 - y1) * (XR - x1) / (x2 - x1);// 求直线与矩形窗口的右边界的交点} else if ((BOTTOM & code) != 0) {// 直线的端点与矩形窗口的下边编码相与!=0y = YB;x = x1 + (x2 - x1) * (YB - y1) / (y2 - y1);// 求直线与矩形窗口的下边界的交点} else if ((TOP & code) != 0) {// 直线的端点与矩形窗口的上边编码相与!=0y = YT;x = x1 + (x2 - x1) * (YT - y1) / (y2 - y1);// 直线的端点与矩形窗口的上// 边编码相与!=0}if (code == code1) {x1 = x;y1 = y;code1 = encode(x, y);} else {x2 = x;y2 = y;code2 = encode(x, y);}}g.drawLine((int) (x1 + 0.5), (int) (y1 + 0.5), (int) (x2 + 0.5),(int) (y2 + 0.5));}二、多边形裁剪的核心代码为:通过点集画直线或者多边形:private void draw() {//通过点集画直线或者多边形for (int i = 1; i < points.size(); i++) {Point p1 = new Point();p1 = points.get(i);int x1 = (int) p1.getX();int y1 = (int) p1.getY();Point p2 = new Point();p2 = points.get(i - 1);int x2 = (int) p2.getX();int y2 = (int) p2.getY();g.drawLine(x1, y1, x2, y2);}}多边形的裁剪函数:private Point[] cutPicture(Point[] point, Point[] edge) {// 剪裁函数,参数为(点集,边)Point[] intersectPoint = new Point[20];//存放交点的集合for (int j = 0; j < 20; j++) {intersectPoint[j] = new Point();}Point s = new Point();Point p = new Point();Point t = new Point();int i = 0;int length = point.length;s = point[length - 1];for (int j = 0; j < length; j++) {p = point[j];if (inside(p, edge)) {// sp在窗口,情况1if (inside(s, edge)) {intersectPoint[i] = p;i += 1;} else {// s在窗口外,情况4t = intersect(s, p, edge);intersectPoint[i] = t;i += 1;intersectPoint[i] = p;i += 1;}} else if (inside(s, edge)) {// s在窗口,p在窗口外,情况3t = intersect(s, p, edge);intersectPoint[i] = t;i += 1;}// 情况2没有输出s = p;}List<Point> tempList = new ArrayList<Point>();for (int k = 0; k < i; k++) {if (intersectPoint[k] != null) {Point pt = intersectPoint[k];tempList.add(pt);}}Point[] temp = new Point[tempList.size()];for (int j = 0; j < tempList.size(); j++) {temp[j] = new Point();temp[j] = tempList.get(j);}intersectPoint = temp;return intersectPoint;}判断点是否在裁剪边的可见侧:private boolean inside(Point point, Point[] edge) {//判断点是否在裁剪边的可见侧// 裁剪边为窗口下边if ((edge[0].y == edge[1].y) && (edge[0].x < edge[1].x)) {if (point.y >= edge[0].y) {return true;}}// 裁剪边为窗口上边if ((edge[0].y == edge[1].y) && (edge[0].x > edge[1].x)) {if (point.y <= edge[0].y) {return true;}}// 裁剪边为窗口右边if ((edge[0].x == edge[1].x) && (edge[0].y < edge[1].y)) {if (point.x <= edge[0].x) {return true;}}// 裁剪边为窗口左边if ((edge[0].x == edge[1].x) && (edge[0].y > edge[1].y)) {if (point.x >= edge[0].x) {return true;}}return false;}直线段与窗口边界求交:private Point intersect(Point s, Point p, Point[] edge) {//直线段与窗口边界求交,并返回交点Point t = new Point();if (edge[0].y == edge[1].y) {// 水平裁剪边t.y = edge[0].y;t.x = s.x + (edge[0].y - s.y) * (p.x - s.x) / (p.y - s.y);} else if (edge[0].x == edge[1].x) {// 垂直裁剪边t.x = edge[0].x;t.y = s.y + (edge[0].x - s.x) * (p.y - s.y) / (p.x - s.x);}return t;}鼠标的监听类(部类):class MouseMonitor extends MouseAdapter {//通过鼠标的单击获取点,并画出直线或者多边形public void mouseClicked(MouseEvent e) {points.add(e.getPoint());if (points.size() > 1) {draw();}}}键盘的监听类(部类):class KeyMonitor extends KeyAdapter {// 键盘控制public void keyPressed(KeyEvent e) {switch (e.getKeyCode()) {case KeyEvent.VK_R:// 清空画布和点集panel.repaint();points.removeAll(points);break;case KeyEvent.VK_W://对裁剪窗口的处理g.setColor(Color.RED);g.drawRect(XL, YB, XR - XL, YT - YB);//存放裁剪窗口的边top = new Point[2];// 存放裁剪窗口的上边top[0] = new Point(XL, YB);top[1] = new Point(XR, YB);right = new Point[2];//存放裁剪窗口的右边right[0] = new Point(XR, YB);right[1] = new Point(XR, YT);bottom = new Point[2];//存放裁剪窗口的下边bottom[0] = new Point(XR, YT);bottom[1] = new Point(XL, YT);left = new Point[2];//存放裁剪窗口的左边left[0] = new Point(XL, YT);left[1] = new Point(XL, YB);break;case KeyEvent.VK_A://对直线段进行裁剪g.setColor(Color.GREEN);Point p1 = points.get(0);Point p2 = points.get(1);lineCut(p1.getX(), p1.getY(), p2.getX(), p2.getY());break;case KeyEvent.VK_B://对多边形进行裁剪source = new Point[points.size()];//得到多边形的点for (int i = 0; i < points.size(); i++) {source[i] = points.get(i);}g.setColor(Color.GREEN);wT = cutPicture(source, top);//得到多边形与裁剪窗口上边的交点wR = cutPicture(wT, right);//得到多边形与裁剪窗口右边的交点wB = cutPicture(wR, bottom);//得到多边形与裁剪窗口下边的交点wL = cutPicture(wB, left);//得到多边形与裁剪窗口左边的交点第二种情况:线段在裁剪窗口的部,线段完全可见。
计算机图形学算法

1.图案填充#include <GL/glut.h> // 设置头文件#include<iostream.h>void init (void) //初始化函数{ glClearColor (1.0, 1.0, 1.0, 0.0); // 设置清屏的颜色(Red,green,blue),但不能让该颜色在显示窗口上出现.glMatrixMode (GL_PROJECTION); //设置投影矩阵.glLoadIdentity (); //单位化上述投影矩阵gluOrtho2D (0.0, 400.0, 0.0, 300.0); //设置具体投影矩阵为平面正交投影4/3}void lineSegment (void) //绘图函数{glClear (GL_COLOR_BUFFER_BIT); // 按glClearColor (1.0, 1.0, 1.0, 0.0);指定的颜色刷新颜色帧缓存glColor3f (1.0, 0.0, 0.0); //设置前景色,即画图的颜色glBegin (GL_LINE_STRIP); //OpenGL绘图命令参数glVertex2i (160, 15); // 指定画线的端点坐标.glVertex2i (10, 140);glVertex2i(100,44);glEnd ( ); // OpenGL绘图结束命令参数glFlush ( ); //在每一画面或场景的结尾处调用,强制前面发出的OpenGL命令开始执行}void yuan(void){ int x,y,r,e;r = 2;x = 0;y = r;e = 1 - r;glClear(GL_COLOR_BUFFER_BIT);glColor3f(1.0,0.0,0.0);glVertex2f(x,y);}void fangge(void){ GLubyte fly[]={ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x01,0xC0,0x06,0xC0,0x03,0x60,0x04,0x60,0x06,0x20,0x04,0x30,0x0C,0x20,0x04,0x18,0x18,0x20,0x04,0x0C,0x30,0x20,0x04,0x06,0x60,0x20,0x44,0x03,0xC0,0x22,0x44,0x01,0x80,0x22,0x44,0x01,0x80,0x22,0x44,0x01,0x80,0x22,0x44,0x01,0x80,0x22,0x44,0x01,0x80,0x22,0x44,0x01,0x80,0x22,0x66,0x01,0x80,0x66,0x33,0x01,0x80,0xCC,0x19,0x81,0x81,0x98,0x0C,0xC1,0x83,0x30,0X03,0X31,0X8c,0Xc0,0X03,0X33,0Xcc,0Xc0,0X06,0X64,0X26,0X60,0X0c,0Xcc,0X33,0X30,0X18,0Xcc,0X33,0X18,0X10,0Xc4,0X23,0X08,0X10,0X63,0xc6,0x08,0x10,0x30,0X0c,0X08,0X10,0X18,0X18,0X08,0X10,0X00,0X00,0X08 };GLubyte halftone[] ={ 0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,0XAA,0XAA,0XAA,0XAA,0X55,0X55,0X55,0X55,};glClear(GL_COLOR_BUFFER_BIT);glColor3f(0.0,0.0,0.0);glRectf(25.0,25.0,125.0,125.0);glEnable (GL_POLYGON_STIPPLE);glColor3f(0.0,0.0,0.0);glPolygonStipple(fly);glRectf(125.0,25.0,225.0,125.0);glPolygonStipple(halftone);glRectf(225.0,25.0,325.0,125.0);glDisable(GL_POLYGON_STIPPLE);glFlush(); }void main (int argc, char** argv) // OpenGL绘图主函数{ glutInit (&argc, argv); // 初始化GLUT库glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); //设置显示模式glutInitWindowPosition (50, 100); //窗口左上角像素坐标glutInitWindowSize (400, 300); // 设置设备显示窗口大小4/3glutCreateWindow ("An Example OpenGL Program"); //创建一个窗口,参数为窗口的标题init ( ); // 函数调用.//glutDisplayFunc (lineSegment); // 绘制当前窗口glutDisplayFunc (fangge);glutMainLoop ( ); //通常用于程序的结尾,表示开始运行程序.显示出所有创建的窗口}2.坐标变换#include <GL/glut.h> // 设置头文件#include<iostream.h>#include<math.h>float p[2][3] = {0,100,50,0,0,50 };//顶点坐标。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2.1.1 生成直线的DDA算法数值微分法即DDA法(Digital Differential Analyzer),是一种基于直线的微分方程来生成直线的方法。
一、直线DDA算法描述:设(x1,y1)和(x2,y2)分别为所求直线的起点和终点坐标,由直线的微分方程得= m =直线的斜率(2-1) 可通过计算由x方向的增量△x引起y的改变来生成直线:x i+1=x i+△x (2-2)y i+1=y i+△y=y i+△x·m (2-3) 也可通过计算由y方向的增量△y引起x的改变来生成直线:y i+1=y i+△y (2-4)x i+1=x i+△x=x i+△y/m (2-5) 式(2-2)至(2-5)是递推的。
二、直线DDA算法思想:选定x2-x1和y2-y1中较大者作为步进方向(假设x2-x1较大),取该方向上的增量为一个象素单位(△x=1),然后利用式(2-1)计算另一个方向的增量(△y=△x·m=m)。
通过递推公式(2-2)至(2-5),把每次计算出的(x i+1,y i+1)经取整后送到显示器输出,则得到扫描转换后的直线。
之所以取x2-x1和y2-y1中较大者作为步进方向,是考虑沿着线段分布的象素应均匀,这在下图中可看出。
另外,算法实现中还应注意直线的生成方向,以决定Δx及Δy是取正值还是负值。
三、直线DDA算法实现:1、已知直线的两端点坐标:(x1,y1),(x2,y2)2、已知画线的颜色:color3、计算两个方向的变化量:dx=x2-x1dy=y2-y14、求出两个方向最大变化量的绝对值:steps=max(|dx|,|dy|)5、计算两个方向的增量(考虑了生成方向):xin=dx/stepsyin=dy/steps6、设置初始象素坐标:x=x1,y=y17、用循环实现直线的绘制:for(i=1;i<=steps;i++){ putpixel(x,y,color);/*在(x,y)处,以color色画点*/x=x+xin;y=y+yin;}五、直线DDA算法特点:该算法简单,实现容易,但由于在循环中涉及实型数的运算,因此生成直线的速度较慢。
//@brief 浮点数转整数的宏实现代码#define FloatToInteger(fNum)((fNum>0)?static_cast<int>(fNum+0.5):static_cast<int>(fNum-0.5))/*!* @brief DDA画线函数** @param pDC [in]窗口DC* @param BeginPt [in]直线起点* @param EndPt [in]直线终点* @param LineCor [in]直线颜色* @return 无*/void CDrawMsg::DDA_DrawLine(CDC *pDC,CPoint &BeginPt,CPoint &EndPt,COLORREF LineCor){l ong YDis = (EndPt.y - BeginPt.y);l ong XDis = (EndPt.x-BeginPt.x);l ong MaxStep = max(abs(XDis),abs(YDis)); // 步进的步数f loat fXUnitLen = 1.0f; // X方向的单位步进f loat fYUnitLen = 1.0f; // Y方向的单位步进f YUnitLen = static_cast<float>(YDis)/static_cast<float>(MaxStep);f XUnitLen = static_cast<float>(XDis)/static_cast<float>(MaxStep);// 设置起点像素颜色p DC->SetPixel(BeginPt.x,BeginPt.y,LineCor);f loat x = static_cast<float>(BeginPt.x);f loat y = static_cast<float>(BeginPt.y);// 循环步进f or (long i = 1;i<=MaxStep;i++){x = x + fXUnitLen;y = y + fYUnitLen;pDC->SetPixel(FloatToInteger(x),FloatToInteger(y),LineCor);}}2.1.2 生成直线的B resenham算法从上面介绍的DDA算法可以看到,由于在循环中涉及实型数据的加减运算,因此直线的生成速度较慢。
在生成直线的算法中,B resenham算法是最有效的算法之一。
B resenham算法是一种基于误差判别式来生成直线的方法。
一、直线Bresenham算法描述:它也是采用递推步进的办法,令每次最大变化方向的坐标步进一个象素,同时另一个方向的坐标依据误差判别式的符号来决定是否也要步进一个象素。
我们首先讨论m=△y/△x,当0≤m≤1且x1<x2时的B resenham算法。
从DDA直线算法可知这些条件成立时,公式(2-2)、(2-3)可写成:x i+1=x i+1 (2-6)y i+1=y i+m(2-7)有两种B resenham算法思想,它们各自从不同角度介绍了B resenham算法思想,得出的误差判别式都是一样的。
二、直线B resenham算法思想之一:由于显示直线的象素点只能取整数值坐标,可以假设直线上第i个象素点坐标为(x i,y i),它是直线上点(x i,y i)的最佳近似,并且x i=x i(假设m<1),如下图所示。
那么,直线上下一个象素点的可能位置是(x i+1,y i)或(x i+1,y i+1)。
由图中可以知道,在x=x i+1处,直线上点的y值是y=m(x i+1)+b,该点离象素点(x i+1,y i)和象素点(x i+1,y i+1)的距离分别是d1和d2:d1=y-y i=m(x i+1)+b-y i(2-8)d2=(y i+1)-y=(y i+1)-m(x i+1)-b (2-9) 这两个距离差是d1-d2=2m(x i+1)-2y i+2b-1 (2-10)我们来分析公式(2-10):(1)当此值为正时,d1>d2,说明直线上理论点离(x i+1,y i+1)象素较近,下一个象素点应取(x i+1,y i+1)。
(2)当此值为负时,d1<d2,说明直线上理论点离(x i+1,y i)象素较近,则下一个象素点应取(x i+1,y i)。
(3)当此值为零时,说明直线上理论点离上、下两个象素点的距离相等,取哪个点都行,假设算法规定这种情况下取(x i+1,y i+1)作为下一个象素点。
因此只要利用(d1-d2)的符号就可以决定下一个象素点的选择。
为此,我们进一步定义一个新的判别式:p i=△x×(d1-d2)=2△y·x i-2△x·y i+c (2-11)式(2-11)中的△x=(x2-x1)>0,因此p i与(d1-d2)有相同的符号;这里△y=y2-y1,m=△y/△x;c=2△y+△x(2b-1)。
下面对式(2-11)作进一步处理,以便得出误差判别递推公式并消除常数c 。
将式(2-11)中的下标i 改写成i+1,得到:p i+1=2△y ·x i +1-2△x ·y i +1+c(2-12)将式(2-12)减去(2-11),并利用x i +1=x i +1,可得:p i+1= p i +2△y-2△x ·(y i +1-y i )(2-13)再假设直线的初始端点恰好是其象素点的坐标,即满足:y 1=m x 1+b(2-14)由式(2-11)和式(2-14)得到p 1的初始值:p 1=2△y-△x(2-15)这样,我们可利用误差判别变量,得到如下算法表示:初始 p 1=2△y-△x (2-16)当p i ≥0时: y i+1=y i +1, x i+1=x i +1, p i+1=p i +2(△y-△x) 否则: y i+1=y i , x i+1=x i +1,p i+1=p i +2△y从式(2-16)可以看出,第i+1步的判别变量p i+1仅与第i 步的判别变量p i 、直线的两个端点坐标分量差△x 和△y 有关,运算中只含有整数相加和乘2运算,而乘2可利用算术左移一位来完成,因此这个算法速度快并易于硬件实现。
三、直线B resenham 算法思想之二:由于象素坐标的整数性,数学点(x i ,y i )与所取象素点(x i ,y ir )间会引起误差(εi ),当x i 列上已用象素坐标(x i ,y ir )表示直线上的点(x i ,y i ),下一直线点B (x i+1,y i+1),是取象素点C (x i+1,y ir ),还是D (x i +1,y (i+1)r )呢?设A 为CD 边的中点,正确的选择:若B 点在A 点上方,选择D 点; 否则,选C 点。
用误差式描述为:ε(x i+1)=BC-AC=(y i+1-y ir)-0.5 (2-8')求递推公式:ε(x i+2)=(y i+2-y(i+1)r)-0.5 = y i+1+m-y(i+1)r-0.5 (2-9')当ε(x i+1)≥0时,选D点,y(i+1)r = y ir+1ε(x i+2)= y i+1+m-y ir-1-0.5=ε(x i+1)+m-1 (2-10')当ε(x i+1)﹤0时,选C点,y(i+1)r = y irε(x i+2)= y i+1+m-y ir-0.5=ε(x i+1)+m(2-11')初始时:ε(x s+1)=BC-AC=m-0.5 (2-12')为了运算中不含实型数,同时不影响不等式的判断,将方程两边同乘一正整数。
令方程两边同乘2·Δx,即d=2·Δx·ε,则:初始时:d = 2·Δy-Δx (2-13')递推式:当d≥0时:{ d=d+2·(Δy-Δx);y++;x++;(2-14')}否则:{ d=d+2·Δy;x++;}实现代码void Bresenhamline (int x0,int y0,int x1, int y1,int color){int x, y, dx, dy;float k, e;dx = x1-x0, dy = y1- y0, k=dy/dx;e=-0.5, x=x0, y=y0;for (i=0; i<=dx; i++){ drawpixel (x, y, color);x=x+1,e=e+k;if (e>=0){ y++, e=e-1;}}}或者将e扩大2dx倍;void Bresenhamline (int x0,int y0,int x1, int y1,int color){int x, y, dx, dy;float k, e;dx = x1-x0, dy = y1- y0, k=dy/dx;e=-dx, x=x0, y=y0;for (i=0; i<=dx; i++){ drawpixel (x, y, color);x=x+1,e=e+2dy;if (e>=0){ y++, e=e-2dx;}}}四、直线B resenham算法实现:条件:0≤m≤1且x1<x21、输入线段的两个端点坐标和画线颜色:x1,y1,x2,y2,color;2、设置象素坐标初值:x=x1,y=y1;3、设置初始误差判别值:p=2·Δy-Δx;4、分别计算:Δx=x2-x1、Δy=y2-y1;5、循环实现直线的生成:for(x=x1;x<=x2;x++){ putpixel(x,y,color) ;if(p>=0){ y=y+1;p=p+2·(Δy-Δx);}else{ p=p+2·Δy;}}五、直线B resenham算法完善:现在我们修正(2-16)公式,以适应对任何方向及任何斜率线段的绘制。