
计算机图形学-基本图元扫描转换-DDA画线法、中点画线法、八分法Bresenham画圆法(用户对话框输入圆心坐标和半径)
计算机图形学-基本图元扫描转换-DDA画线法、中点画线法、八分法Bresenham画圆法(用户对话框输入圆心坐标和半径)
1、DDA画线
在右侧资源视图Menu目录下的IDR_MAINFRAME文件,双击打开,出现菜单列。点击空白的“请在此处键入”,输入“直线”,按下回车。进入绘图下的子菜单,输入“DDA画线”。对新建的“DDA画线”,右键,选择“添加事件处理程序”。找到的 “// TODO: 在此添加命令处理程序代码”,输入如下代码:
//DDA画线法
CDC* pDC = GetDC(); // 获得设备指针
CRect rectDlg;
GetClientRect(rectDlg); // 获得窗体的大小
int pointWidth = rectDlg.Width(); // 获取窗体宽度
int pointHeight = rectDlg.Height(); // 获取窗体高度
RedrawWindow(CRect(0, 0, pointWidth, pointHeight));
int x0 = 100, y0 = 100, x1 = 300, y1 = 200, c = RGB(255, 0, 0); //定义直线两端点和直线颜色(红色)
float x, y;
float dx, dy, k;
dx = (float)(x1 - x0);
dy = (float)(y1 - y0);
k = dy / dx;//计算斜率
y = y0; x = x0;
if (abs(k) < 1)
{
for (; x <= x1; x++)
{
pDC->SetPixel(x, int(y + 0.5), c);
y = y + k;
}//x自增,y=y+k
}
if (abs(k) >= 1)
{
for (; y <= y1; y++)
{
pDC->SetPixel(int(x + 0.5), y, c);
x = x + 1 / k;
}
}
ReleaseDC(pDC); //释放设备指针
效果:
2、中点画线
算法思路
中点画线法的算法流程有:输入线段的起点和终点、计算线段的斜率和长度、判断斜率是否小于1或大于等于1、根据斜率的不同,采用不同的算法计算中点的坐标、根据中点的坐标,计算下一个像素点的坐标、重复前两步骤,直到绘制到终点为止、输出绘制好的线条。
假设直线方程为F(x,y)=ax+by+c=0,已确定像素点P的位置,如图3-2-1,判断下一像素点位置需要判断交点Q与中点M的位置关系,构造判别式d=F(M)=F(xp+1,yp+0.5),如果d > 0,则中点(x,ym)在L(Q)的上方,此时应该取右边的像素点P1(xp+1,yp),即x加1、y不变。此时,d的值增加d1,即d=d+d1。如果d<0,则中点(xm,ym)在L(Q)的下方,应该取右上方的像素点P2(xp+1,yp+1),即x和y均加1。此时,d的值增加d2,即d=d+d2。如下图:
在右侧资源视图Menu目录下的IDR_MAINFRAME文件,双击打开,出现菜单列。点击上一步新建好的“DDA画线”按钮,回车,输入“中点画线”,右键,选择“添加事件处理程序”。找到的 “// TODO: 在此添加命令处理程序代码”,输入如下代码:
//中点画线
CRect rectDlg;
GetClientRect(rectDlg); // 获得窗体的大小
int pointWidth = rectDlg.Width(); // 获取窗体宽度
int pointHeight = rectDlg.Height(); // 获取窗体高度
RedrawWindow(CRect(0, 0, pointWidth, pointHeight));
CDC* pDC = GetDC();
int x0=100, y0 = 100, x1 = 500, y1 = 600, c = RGB(0, 0, 0);
//CString IntType;
//IntType.Format(_T("x0 %d,y0 %d, x1 %d,y1 %d"), x0,y0,x1,y1);
//MessageBox(IntType);
float 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;
pDC->SetPixel(x, y, c);
while (x < x1) {
if (d < 0) {
x++;
y++;
d += d2;
}
else {
x++;
d += d1;
}
pDC->SetPixel(x, y, c);
}
//ReleaseDC(pDC);
效果:
补充说明:每次画线前,我加了一个清空画板的操作,这样上一次的操作就不会再显示了,代码:
CRect rectDlg;
GetClientRect(rectDlg); // 获得窗体的大小
int pointWidth = rectDlg.Width(); // 获取窗体宽度
int pointHeight = rectDlg.Height(); // 获取窗体高度
RedrawWindow(CRect(0, 0, pointWidth, pointHeight));
3、Bresenham画圆
我在画圆函数中,将圆心和半径设置的用户自定义输入获取。定义函数circlePoint,在其中画出8个1/8圆弧,然后利用对称关系将这八个圆弧组成一个圆。用对话框的日志文件circleBreDlg获取圆心坐标和半径,在函数OnCirclebre()中画圆。
算法思路
Bresenham画圆算法是一种用于绘制圆形的算法,它适合于生成整圆,我使用8路对称法,只计算出90°~45°内的点,移动方向为+x,-y。该算法的核心思想是以坐标原点(0,0)为圆心的圆可以通过0度到45°的弧计算得到,即x从0增加到半径,然后利用对称性计算余下的七段圆弧。具体实现步骤如下:1‘定义圆的半径R、2‘初始化一个空的二维数组用来存储像素点、3‘对于每个x值从0到R,计算对应的y值、4‘根据计算出的(x,y)坐标,在二维数组中标记该像素点已被访问过、5‘利用对称性,通过旋转和翻转等方式,生成圆上其他像素点的坐标、重复步骤3到5,直到所有像素点都被访问过。最后将二维数组中所有标记过的像素点绘制到屏幕上。
(1)设置对话框,获取数据
在资源视图中,找到Dialog文件夹,右键点击插入。
分别拖出四个静态框,三个编辑框,用于提示用户输入数据,并获取。点击新建好的静态框,右键属性,在描述文字那里依次输入:请输入圆的坐标和半径,X:,Y:。编辑框右键属性,编辑ID,我便于区分,把X的ID就写的IDC_X,Y和R的以此类推。
(2)添加类向导
点击项目菜单下的类向导,类名选择CAboutDlog。给对话框起名:circleBreDlg点击ok。再次打开类向导,把对话框建立的成员变量IDC_X,IDC_Y和IDC_R添加给新建的类,添加时类别选择值,类型输入int,最后点击确定。
(3)定制菜单
找到Menu目录下的IDR_MAINFRAME文件,双击打开,输入“画圆”,回车,再输入“Bresenham”。右键属性,将ID改为“ID_CircleBre”
(4)建立消息映射
打开类向导,类名选择C+工程名+View,命令处找到按钮的ID:ID_CircleBre,消息点击COMMAND,点击右侧添加事件处理程序。点击确定。
(5)代码实现
如果不想画出来的圆弧是8个颜色(八分法画圆),可以把8句dc.SetPixel里面RGB的颜色换成一样的。
void CMFCApplication2View::OnCirclebre()
{
// TODO: 在此添加命令处理程序代码
circleBreDlg dlg;
if (dlg.DoModal() == IDOK) {//输入框显示时
//给全局变量赋值,获取对话框声明的变量
R = dlg.m_CircleBreR;
x0 = dlg.m_CircleBreX;
y0 = dlg.m_CircleBreY;
}
CString str;
str = "Bresenham画圆法";
//str.Format(_T("%d"), a);
AfxGetMainWnd()->SetWindowText(str);//设置窗口文字
RedrawWindow();//绘制窗口
circleBre();//调用画圆函数
}
void CMFCApplication2View::circleBre() {
int x, y, d;
x = 0;
y = R;
d = 3 - 2 * R;
while (x < y) {
circlePoint(x, y);
if (d < 0) {
d = d + 4 * x + 6;
}
else {
d = d + 4 * (x - y) + 10;
y--;
}
x++;
}
if (x == y) {
circlePoint(x, y);
}
}
void CMFCApplication2View::circlePoint(int x, int y)
{
// TODO: Add your command handler code here
CClientDC dc(this); //添加上下文,确定画布
//COLORREF rgb = RGB(0 + rand() % 255, 0 + rand() % 255, 0 + rand() % 254); //添加画笔颜色
dc.SetPixel(x0 + x, y0 + y, RGB(255,0,0));
dc.SetPixel(x0 + y, y0 + x, RGB(0,255,0));
dc.SetPixel(x0 + y, y0 - x, RGB(0,0,255));
dc.SetPixel(x0 + x, y0 - y, RGB(128,56,23));
dc.SetPixel(x0 - x, y0 - y, RGB(36,56,89));
dc.SetPixel(x0 - y, y0 - x, RGB(36,99,236));
dc.SetPixel(x0 - y, y0 + x, RGB(23,125,3));
dc.SetPixel(x0 - x, y0 + y, RGB(129,23,0));
}
(6)效果展示:
点击画圆下的Bresenham按钮,弹出对话框
输入圆心坐标(300,300),半径200,绘制如下圆:
更多推荐
所有评论(0)