计算机图形学是一门研究如何利用计算机表示,生成,处理和显示的图形的学科。 代表着计算机工业的发展水平。
**图形:**计算机图形学的研究对象。
计算机游戏,计算机辅助设计(CAD or CAM),计算机艺术,虚拟现实,计算机辅助教学
采用了液晶控制透光度技术来生成图形的显示器。
CRT显示器具有价格低,亮度高,视角宽,使用寿命高的优点。而LCD显示器则有体积小,重量轻,图像无闪烁,辐射低的优点。缺点是视角稍窄,使用寿命短。
virtual int SetNMapMode(int nMapMode)
返回值:原映射模式,用宏定义值来表示
virtual CSize SetWindowExt(int cx,int cy);
virtual CSize SetWindowExt(SIZE size);
参数:cx窗口x范围的逻辑坐标,cy窗口y范围的逻辑坐标;size 是窗口的SIZE或CSIZE对象。
返回值:原窗口范围内的CSIZE对象。
3. 设置视区范围函数
virtual CSize SetViewportExt(int cx,int cy);
virtual CSize SetViewportExt(SIZE size);
参数:cx视区x范围的逻辑坐标,cy视区y范围的逻辑坐标;size 是视区的SIZE或CSIZE对象。
返回值:原窗视区范围内的CSIZE对象。
CPoint SetWindowOrg(int x,int y);
CPoint SetWindowOrg(POINT point);
参数:x,y是窗口新原点坐标;point是窗口新原点的POINT结构或者CPoint对象。
返回值:原窗口原点的CPoint对象。
5. 设置视区原点函数
virtual CPoint SetWindowOrg(int x,int y);
virtual CPoint SetWindowOrg(POINT point);
参数:x,y是视区新原点坐标;point是视区新原点的POINT结构或者CPoint对象。
返回值:原视区原点的CPoint对象。
注意点:窗口可以理解为一种逻辑坐标下的句型区域,而视区是设备坐标系下的矩形区域。根据窗口和视区的大小可以确定x方向和y方向的比例因子。
设置x轴正向向右,y轴正向向上,客户区中心为中心原点。
pDC->setWindowExt(rect.Width(),rect.Height());
pDC->setViewportExt(rect.Width(),-rect.Height());
pDC->setViewportOrg(rect.Width()/2,rect.Height()/2);
把一个100200的窗口中的图形显示到200px200px的视区中
窗口映射到视区中,y方向的比例为1(不变),x方向的比例为2 (放大2倍)。
一个逻辑单位在y方向映射为一个像素,x方向都映射为2个像素
pDC->SetMapMode(MM_AISOTROPIC);
pDC->SetWindowExt(100,200);
pDC->SetViewportExt(200,200);
保持X轴正向向右不变,当Y轴正向向下时 SetViewportOrg(x, y);与
SetWindowOrg(-x, -y);等价
当Y轴正向向上时 SetViewportOrg(x, y);与SetWindowOrg(-x, y);等价
Cpen NewPen,*OldPen;
NewPen.CreatePen(PS_SOLID,1,RGB(0,0,255));//创建蓝色画笔
OldPen=pDC->SelectObject(&NewPen);//选入对象
...
pDC->SelectObject(OldPen);//保存原画笔
NewPen.DeleteObject();
设当前屏幕上最逼近直线的像素点为Pi(xi,yi),下一个像素点Pi+1(xi+1,yi+1)相较于前一个像素点的坐标每次在主位移方向上+or-1,另一个方向上是否+or-1取决于中点偏差判别式的值。
若直线斜率绝对值<=1,直线在x方向上变化快,以x为主位移方向。否则,以y为主位移方向。
从Pi(xi,yi)点出发选择下一像素时,需将Pu和Pd的中点M(xi+1,yi+0.5)代入隐函数方程,构造中点误差项di。
di = F(xi+1,yi+0.5) = yi+0.5-k(xi+1)-b
当di < 0时,中点M在直线的下方,Pu点离直线距离更近,下一像素点应选取Pu,即y向上走一步;di = 0时,选取两点均可。否则,选取Pd点,y方向上不移动。
因此
void Bresenham(int x0,int y0,int x1,int y1){
int dx = x1-x0,dy = y1-y0;
int x = x0,y = y0;
double k = 1.0*dy/dx;
double d;
//绘制斜率k为0<=k<=1的直线
if(k >= 0 && k <= 1.0){
//设置直线段的颜色
COLORREF clr = RGB(255,0,0);
d = 0.5-k;
//不包括中点
for(x = x0;x < x1;x++){
pDC->SetPixel(Round(x),Round(y),clr);
if(d < 0){
y++;
d += 1-k;
}
else{
d-=k;
}
}
}
}
本算法是考虑45°的圆弧及第一象限x在[-,R/sqrt(2)]的1/8圆弧、
(1)当di <0时,下一中点的坐标为:M(xi+2,yi-0.5)。所以下一步中点偏差判别式为:
(2)di >= 0时,下一中点的坐标为:M(xi+2,yi-1.5)。所以下一步的中点误差判别式为:
中点偏差判别式的初始值
//画中点的Bresenham算法
void CTestView::MBCircle(double R,CDC *pDC){
double d;
d = 1.25-R;
int x = 0,y = R;
for(x = 0; x <= y;x++){
//调用八分法画圆子函数
CirclePoint(x,y,pDC);
if(d < 0){
d += 2*x+3;
}
else{
d += 2*(x-y)+5;
y--;
}
}
}
void CTestView::CirclePoint(int x,int y,CDC *pDC){
//圆心坐标
CP2 pc = CP2((p0.x+p1.x)/2.0,(p0.y+p1.y)/2.0);
//定义圆的边界颜色
COLORREF clr = RGB(0,0,255);
pDC->SetPixelV(Round(x+pc.x),Round(y+pc.y),clr);
pDC->SetPixelV(Round(y+pc.x),Round(x+pc.y),clr);
pDC->SetPixelV(Round(y+pc.x),Round(-x+pc.y),clr);
pDC->SetPixelV(Round(x+pc.x),Round(-y+pc.y),clr);
pDC->SetPixelV(Round(-x+pc.x),Round(-y+pc.y),clr);
pDC->SetPixelV(Round(-y+pc.x),Round(-x+pc.y),clr);
pDC->SetPixelV(Round(-y+pc.x),Round(x+pc.y),clr);
pDC->SetPixelV(Round(-x+pc.x),Round(y+pc.y),clr);
}
中点偏差判别式的初值
中点偏差判别式的初值:
void CTestView::MBEllipse(CDC *pDC){
int x,y,a,b;
double d1,d2;
x = 0,y = b;
d1 = b*b+a*a*(-b+0.25);
EllipsePoint(x,y,pDC);
//椭圆前半段
while(b*b*(x+1) 0){
if(d2 <0){
d2+=b*b*(2*x+2)+a*a*(-2*y+3);
x++;
}
else{
d2 += a*a*(-2*y+3);
}
y--;
EllipsePoint(x,y,pDC);
}
}
//四分法画椭圆子函数
void CTestView::EllipsePoint(double x,double y,CDC *pDC){
//椭圆中心坐标
CP2 pc = CP2((p0.x+p1.x)/2.0,(p0.y+p1.y)/2.0);
//定义椭圆的颜色
COLORREF clr = RGB(0,0,255);
pDC->SetPixelV(Round(x+pc.x),Round(y+pc.y),clr);
pDC->SetPixelV(Round(-x+pc.x),Round(y+pc.y),clr);
pDC->SetPixelV(Round(x+pc.x),Round(-y+pc.y),clr);
pDC->SetPixelV(Round(-x+pc.x),Round(-y+pc.y),clr);
}
(1)顶点表示法
(2)点阵表示法
(3)多边形的扫描变换
将多边形的描述从顶点表示法变换到点阵表示法的过程,叫做多边形的扫描转换。即从多边形的顶点信息出发,求出多边形内部的各个像素点信息。
一般原理:
按照扫描线从小到大的移动顺序,计算当前扫描线与多边形各边的交点,然后按照交点用指定的颜色点亮区间内的所有像素,完成填充工作。
边界像素处理原则:下闭上开,左闭右开
x | ymax | 1/k | next |
---|
有效边的数据结构定义如下:
//有效边类
class AET{
public:
AET();
virtual ~AET();
double x;
int ymax;
double k;
AET *next;
};
有效边表给出了扫描线和有效边交点坐标的计算方法,但是没有给出新边出现的位置坐标,为了确定在哪条扫描线上插入了新边,就需要构造一个边表,用以存放扫描线上多边形各条边出现的信息。
边表的表示方法:
桶的数据结构定义如下:
class Bucket{
public:
Bucket();
virtual ~Bucket();
//扫描线
int ScanLine();
//桶上的边表指针
Bucket *next;
};
将每一边放入与该边最小y坐标相对应的桶中。
x|ymin | ymax | 1/k | next |
---|
原理:求出多边形的每条边与扫描线的交点,然后将交点右侧的所有像素颜色全部取为反色。按任意顺序处理完多边形所有边后,就完成了多边形填充任务。
原理:用点阵表示的多边形区域,如果其内部像素具有同一种颜色,而边界像素具有另一种像素,可以使用种子填充算法进行填充。种子填充算法是从区域内任意一个种子像素开始,由内向外将填充色扩充到整个多边形区域。
从多边形区域内任意一个种子像素点出发,通过访问其左上右下这4个邻接点可以遍历区域内所有像素。
从多边形区域内任意一个种子像素点出发,通过访问其左,左上,上,右上,右,右下,下,左下这8个邻接点可以遍历区域内所有像素点。
先将种子像素入栈。种子像素为栈底像素,如果栈不为空,执行如下三步:
先将种子像素入栈,种子像素为栈底像素,如果栈不为空,执行如下4步: