计算机图形学实验一绘制任意斜率的直线段
程序员文章站
2022-03-22 16:24:52
...
一、实验目的
(1)掌握任意斜率直线段的重点 Bresenham 扫描转换算法;
(2)掌握 Cline 直线类的设计方法;
(3)掌握状态栏编程方法。
二、实验步骤
(1)创建MFC应用程序
(2)定义CLine类
- 添加消息处理的处理程序
三、实验结果
四、实验体会
在本次实验中,通过不断的探索和实践,我学会了如何创建一个MFC应用程序,将理论运用于实践,掌握了直线类的设计方法,学会了如何绘制任意斜率的方法,虽然过程很艰辛,遇到了许多困难,但是最终通过不断的努力将实验完成了,收获良多。
附录:源代码
CLine.cpp
// 隐函数F(x,y)=y-kx-b,计算误差项
double CLine::getDistance(double x, double y)
{
return y - m_k * x - m_b;
}
// 调用CDC对象的MoveTo(),移动到起点
void CLine::moveTo(CDC *&pDC)
{
pDC->MoveTo(m_start);
}
// 使用直线扫描算法绘制直线
void CLine::lineTo(CDC *&pDC)
{
//如果直线为垂线或是平行线或是k=1的直线
if ((m_end.x - m_start.x) == 0 || (m_end.y - m_start.y) == 0 ||
(m_end.x - m_start.x) == (m_end.y - m_end.y) ||
(m_end.x - m_start.x) == -(m_end.y - m_end.y))
pDC->LineTo(m_end);
else
{
m_k = ((double)(m_end.y - m_start.y)) / (m_end.x - m_start.x);
m_b = m_start.y - m_k * m_start.x;
if (0 < m_k && m_k < 1)
kOne(pDC);
else if (m_k > 1)
kTwo(pDC);
else if (-1 < m_k && m_k < 0)
kThree(pDC);
else if (m_k < -1)
kFour(pDC);
}
}
// 设置直线起点
void CLine::setStartPoint(CPoint point)
{
this->m_end = point;
}
// 设置直线终点
void CLine::setEndPoint(CPoint point)
{
this->m_start = point;
}
// 绘制直线斜率在0<k<1范围
void CLine::kOne(CDC *&pDC)
{
//始终保持起点X坐标小于Y坐标
if (m_start.x > m_end.x)
{
CPoint tmp = m_start;
m_start = m_end;
m_end = tmp;
}
double d = 0;
COLORREF color = RGB(0, 0, 0); //设置直线的颜色
CPoint next = m_start; //记录起始点
pDC->SetPixelV(next, color); //绘制起始点
for (int i = m_start.x + 1; i <= m_end.x; i++)
{
next.x++; //以X轴为主位移方向
if (d <= 0) //直线位于中点误差上方
next.y++; //取上面那个点
pDC->SetPixelV(next, color); //绘制点
d = getDistance((double)next.x + 1, next.y + 0.5); //下一个中点
}
}
// 绘制直线斜率在k>1范围
void CLine::kTwo(CDC *&pDC)
{
if (m_start.y > m_end.y)
{
CPoint tmp = m_start;
m_start = m_end;
m_end = tmp;
}
double d = 0;
COLORREF color = RGB(0, 0, 0);
CPoint next = m_start;
pDC->SetPixelV(next, color);
for (int i = m_start.y + 1; i <= m_end.y; i++)
{
next.y++;
if (d > 0)
next.x++;
pDC->SetPixelV(next, color);
d = getDistance(next.x + 0.5, (double)next.y + 1);
}
}
// 绘制直线斜率在-1<k<0范围
void CLine::kThree(CDC *&pDC)
{
if (m_start.x < m_end.x)
{
CPoint temp = m_start;
m_start = m_end;
m_end = temp;
}
double d = 0;
COLORREF color = RGB(0, 0, 0);
CPoint next = m_start;
pDC->SetPixelV(next, color);
for (int i = m_start.x - 1; i >= m_end.x; i--)
{
next.x--;
if (d < 0)
next.y++;
pDC->SetPixelV(next, color);
d = getDistance((double)next.x - 1, next.y + 0.5);
}
}
// 绘制直线斜率在k<-1范围
void CLine::kFour(CDC *&pDC)
{
if (m_start.y < m_end.y)
{
CPoint tmp = m_start;
m_start = m_end;
m_end = tmp;
}
double d = 0;
COLORREF color = RGB(0, 0, 0);
CPoint next = m_start;
pDC->SetPixelV(next, color);
for (int i = m_start.y - 1; i >= m_end.y; i--)
{
next.y--;
if (d < 0)
next.x++;
pDC->SetPixelV(next, color);
d = getDistance(next.x + 0.5, (double)next.y - 1);
}
}
消息处理程序:
鼠标左键按下
鼠标左键松开
鼠标移动时显示坐标:
void CMFCApplication1View::OnLButtonDown(UINT nFlags, CPoint point)
{
// 鼠标按下记录起点
this->line.setStartPoint(point);
CView::OnLButtonDown(nFlags, point);
}
void CMFCApplication1View::OnLButtonUp(UINT nFlags, CPoint point)
{
// 鼠标松开记录终点
this->line.setEndPoint(point);
CDC *pDC = GetDC();
this->line.moveTo(pDC);
this->line.lineTo(pDC);
CView::OnLButtonUp(nFlags, point);
}
void CMFCApplication1View::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CString stringX, stringY;
CMainFrame * pFrame = (CMainFrame *)AfxGetMainWnd();
CMFCStatusBar * pStatus = &pFrame->m_wndStatusBar;
if (pStatus != NULL)
{
//_T是一个宏,作用是让你的程序支持Unicode编码(双字节编码)
stringX.Format(_T("x=%d"), point.x);
stringY.Format(_T("y=%d"), point.y);
CClientDC dc(this);
CSize sizeX = dc.GetTextExtent(stringX);
CSize sizeY = dc.GetTextExtent(stringY);
pStatus->SetPaneInfo(1, nFlags, SBPS_NORMAL, sizeX.cx);
pStatus->SetPaneText(1, stringX);
pStatus->SetPaneInfo(2, nFlags, SBPS_NORMAL, sizeY.cx);
pStatus->SetPaneText(2, stringY);
}
CView::OnMouseMove(nFlags, point);
}
下一篇: 批处理(bat)命令学习的一些总结