计算机图形学实验三 《交互式绘制多边形》
这个只是先行版,最近比赛太多了有点忙不过来,讲得不好还请包含
视频讲解:咕咕咕~
一.交互式技术
人机交互就是指人与计算机之间使用某种对话语言,以一定的交互方式,为完成确定任务的人与计算机之间的信息交换过程。
1.消息响应函数
消息响应函数就是收到某些指定消息的时候,做出某些动作的函数,也叫消息处理函数。
有两种方法去添加消息响应函数一种是用户手动添加两个文件((.h)和 (.cpp))的内容,
一种就是用MFC自带的这里只说自带的且常用的。
消息响应函数有很多这里介绍常用的:
WM_LBUTTONDOWN//鼠标按下左键的消息
WM_LBUTTONUP//鼠标左键弹起的消息
//有左键就有右键和上面一样就是L换成R
WM_MOUSEMOVE//鼠标移动消息
//WM就是windows message的意思简单地说就比如第一个就是当你鼠标按下左键的时候
//就会做出对应的响应
接下来说一下如何添加

点击类向导然后
类名切换成你的View类如果你的项目叫Test那这个就是TestView类,然后点击消息,在那个搜索消息框里面搜索要添加的函数,点击之后右边现有处理程序框就会显示,然后点确定就好了。
以按下左键消息函数为例:
void CInteractionView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CDC* pDC=GetDC();
pDC->LineTo(point);
CView::OnLButtonDown(nFlags, point);
}
这样写的意思就是当你按下左键的时候就会画一条直线。
2.橡皮筋
VID_20220321_205431
这是我们想实现的结果,就是交互式的绘制多边形,大概思路就是用MouseMove(鼠标移动消息响应函数)去实现随着鼠标移动线向橡皮筋一样去实时的绘制,然后按下左键去确定点。
先看MouseMove
void CInteractionView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CDC* pDC = GetDC();
pDC->LineTo(point);
CView::OnMouseMove(nFlags, point);
}
这么写的意思就是移动到那线就画到哪那他就会这样
VID_20220321_210459
你会发现之前的线还在残留且不连续,假如你写个代码就绘制一条线那也会出现屏闪的情况
VID_20220321_212150
所以这里我们引入双缓冲技术
双缓冲
双缓冲是指一个显示缓冲区(显示设备上下文)和一个内存缓冲区(内存设备上下文)
在图形图像显示过程中,计算机从显示缓冲区取数据然后显示,很多图形的操作都很复杂需要大量的计算,很难访问一次显示缓冲区就能写入待显示的完整图形数据,通常需要 多次访问显示缓冲区,每次访问时写入最新计算的图形数据。而这样造成的后果是一个需要复杂计算的图形,你看到的效果可能是一部分一部分地显示出来的,造成很大的闪烁不连贯。 而使用双缓冲,可以使你先将计算的中间结果存放在另一个缓冲区中,但全部的计算结束,该缓冲区已经存储了完整的图形之后,再将该缓冲区的图形数据一次性复制到显示缓冲区
双缓冲就是用来解决单缓冲擦除图像时带来的屏幕闪烁问题
有些人可能会用SetROP2(R2_NOT)来实现这个原理就是清楚上一次绘制的案但毕竟不是我们自己写的所以这里我来讲如何自己实现双缓冲
现在TestView.h头文件(你的工程名字叫啥就是啥view)声明DoubleBuffer函数

然后再TestView.cpp源文件去实现对于函数代码
void CInteractionView::DoubleBuffer(CDC* pDC)//双缓冲
{
CRect rect;//定义客户区
GetClientRect(&rect);//获得客户区的大小
CDC MemDC;//内存设备上下文
CBitmap NewBitmap, * pOldBitmap;//内存中承载图像的临时位图
MemDC.CreateCompatibleDC(pDC);//建立与屏幕pDC兼容的MemDC
NewBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());//创建兼容位图
pOldBitmap = MemDC.SelectObject(&NewBitmap); //将兼容位图选入MemDC
MemDC.FillSolidRect(rect, pDC->GetBkColor());//按原来背景填充客户区,否则是黑色
DrawObject(pDC);//这是我写的一个绘制图形的函数
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &MemDC, 0, 0, SRCCOPY);//将内存位图拷贝到屏幕
MemDC.SelectObject(pOldBitmap);//恢复位图
NewBitmap.DeleteObject();//删除位图
MemDC.DeleteDC();//删除MemDC
ReleaseDC(pDC);//释放DC
}
这样就实现了双缓冲机制,代码都有注释不是什么高深的东西就是字面意思,不要想得太复杂也不用纠结调用的函数原理是啥你只需要知道他有啥用就行,如果看不懂注释的意思那就不要强求自己了你就当一个模板记住就行,要用的时候直接复制下来就行。
3.引力域
我们绘制的是一个封闭的多边形,但是最后要封闭的时候你很难精确的去点到那个起点那个像素点,所以我们这里引入引力域技术,效果就是在起点周围你点击鼠标他就会自动连上起点然后封闭。
很简单具体看我的OnLButtonDown函数
void CInteractionView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//如果你有起点(其实这里应该判断至少有三个点才能封闭)然后鼠标当前点在起点
//为中心边长为10像素的正方形时你点击就会自动连上起点形成封闭
if (bLBDown && abs(point.x - P[0].x) <= 5 && abs(point.y - P[0].y) <= 5) {
P[nCount] = P[0];//P[]数组是存所有点的,ncount是点的个数也是存当前点的下标
is_Close = true;//is_Close用来判断封闭,这里封闭了所以将值改为true
}
else P[nCount++] = point;//如果没在那个范围就正常存点
bLBDown = TRUE;//只要你点击了就肯定有起点了吗,这个就是用来判断是否有起点了
CView::OnLButtonDown(nFlags, point);
}
那就说完了我把我的其他的代码发出来你们可以自己试试玩玩
OnMouseMove:
void CInteractionView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CDC* pDC = GetDC();
if (bLBDown) {
if (abs(point.x - P[0].x) <= 5 && abs(point.y - P[0].y) <= 5) {
SetCursor(LoadCursor(NULL, IDC_HAND));//这一段的意思就是如果鼠标到
//指定引力域了会将鼠标变成手指形状加强我们的人机交互体验
}
}
if (!is_Close)P[nCount] = point;//只要没闭合就画线
ReleaseDC(pDC);//释放DC
Invalidate(FALSE);//不擦除背景
CView::OnMouseMove(nFlags, point);
}
DrawObject:
void CInteractionView::DrawObject(CDC* pDC)//绘制多边形
{
pDC->SelectStockObject(GRAY_BRUSH);//画刷设置为灰色等会说为啥要用画刷
//P[]是一个CPoint数组存了我要绘制的点
//这个代码就是把P数组存的点用线连接绘制出来
for (int i=0;i<=nCount;i++) {
if (!i) {
//P[0]是起点所以是MoveTo先移动到第一个点
pDC->

本文详细介绍了计算机图形学中的交互式多边形绘制,包括消息响应函数、橡皮筋效果、引力域技术。此外,重点阐述了有效边表填充算法,包括X扫描线算法、动态链表冒泡排序、桶表和边表的构建,以及填充流程。文章通过实例代码解析了整个过程,适合对图形学感兴趣的读者深入理解。
最低0.47元/天 解锁文章
6317





