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,绘制如下圆:

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐