您的位置:首页 > 其它

直线中点Bresenham算法

2018-03-14 12:50 453 查看
课程名称计算机图形学
班级 实验日期 
姓名 学号 实验成绩 
实验名称直线中点Bresenham算法
实验目的及要求斜率0≤k≤1直线的中点Bresenham算法。
任意斜率直线段绘制算法。
颜色类的定义与调用方法。
直线类的定义与调用方法。
鼠标按键消息映射方法。
  实验内容1、案例描述
在屏幕客户区内按下鼠标左键赞扬直线的起点,移动鼠标指针到直线终点上,弹起鼠标左键绘制任意斜率的直线段。
2、功能说明
(1)设计CRGB类其成员变量为double型的红绿蓝分量red,green和blue,将red,green和blue分量分别规范到[0,1]区间。<
4000
/span>
(2)设计Cline直线类,其成员变量为直线段的起点坐标P0和终点坐标P1,成员函数为MoveTo()和LineTo()函数。
(3)Cline类的LineTo()函数使用中点Bresenham算法绘制任意斜率的直线段,包括k=±∞,k>1,0≤�≤1, -1≤�<0和k<-1这5种情况。
(4)自定义屏幕二维坐标系,原点位于客户区中心,x轴水平向右为正,y轴垂直向上为正。直线段的起点坐标和终点坐标相对于屏幕客户区中心定义。
  算法描述                      及实验步骤  1、案例分析
MFC提供的CDC类的成员函数MoveTo()和LineTo()函数用于绘制傻任意斜率的直线段,直线段的颜色由所选用的画笔指定。MoveTo()函数移动当前点到参数(x,y)所指定的点,不画线;LineTo()函数从当前点画一直线段到参数(x,y)所指定的点,但不包括(x,y)。
本案例通过定义Cline类来模拟CDC类绘制任意斜的直线段,采用直线中点Bresenham算法。
2、算法设计
对于0≤�≤1的直线段,中点Bresenham算法如下:
(1)使用鼠标选择起点坐标p0(x0,y0)和终点坐标p1(x1,y1)。要求起点的的坐标小于等于终点的x坐标。
(2)定义直线段当前点坐标x,y,定义中点误差项d,定义直线斜k,定义像素点颜色clr。
(3)x=x0,y=y0,计算d=0.5-k,k=(y1-y0)/(x1-x0),
clr=CRGB(0,0,1)
(4)绘制点(x,y),判断d的符号。若d<0,则(x,y)更新为(x+1,y+1),d更新为d+1-k;否则(x,y)更新为(x+1,y),d更新为d-k。
(5)如果当前点x<x1,重复步骤(4),否则结束。
3、设计CRGB类
为了规范颜色的处事,定义了CRGB类,重载了“+”,“-”、“*”、“\”、“+=”、“-=”、“*=”、“/=”运算符。成员函数Normalize()将颜色分量red,green,blue规范到[0,1]闭区间内。
RGB.h
#pragma once
class CRGB
{
public:
CRGB();
CRGB(double, double, double);
~CRGB();
 
friend CRGB operator + (const CRGB&, const  CRGB&);
friend CRGB operator - (const CRGB&, const  CRGB&);
friend CRGB operator * (const CRGB&, const  CRGB&);
friend CRGB operator * (const CRGB&, double);
friend CRGB operator * (double, const  CRGB&);
friend CRGB operator / (const CRGB&, double);
friend CRGB operator += (const CRGB&, const  CRGB&);
friend CRGB operator -= (const CRGB&, const  CRGB&);
friend CRGB operator *= (const CRGB&, const  CRGB&);
friend CRGB operator /= (const CRGB&, double);
void Normalize();
 
 
public:
double red;
double green;
double blue;
};
RGB.cpp
#include "stdafx.h"
#include "RGB.h"
 
 
CRGB::CRGB()
{
red = 1.0;
green = 1.0;
blue = 1.0;
}
 
CRGB::~CRGB()
{}
 
CRGB::CRGB(double r, double g, double b)
{
red = r;
green = g;
blue = b;
}
 
CRGB operator +(const CRGB &c1, const CRGB &c2)
{
CRGB c;
c.red = c1.red + c2.red;
c.green = c1.green + c2.green;
c.blue = c1.blue + c2.blue;
return c;
}
 
CRGB operator - (const CRGB &c1, const  CRGB &c2)
{
CRGB c;
c.red = c1.red - c2.red;
c.green = c1.green - c2.green;
c.blue = c1.blue - c2.blue;
return c;
}
 
CRGB operator * (const CRGB&c1, const  CRGB&c2)
{
CRGB c;
c.red = c1.red * c2.red;
c.green = c1.green * c2.green;
c.blue = c1.blue * c2.blue;
return c;
}
 
CRGB operator * (const CRGB&c1, double k)
{
CRGB c;
c.red = c1.red*k;
c.green = c1.green*k;
c.blue = c1.blue*k;
return c;
}
 
CRGB operator * (double k, const  CRGB&c1)
{
CRGB c;
c.red = c1.red*k;
c.green = c1.green*k;
c.blue = c1.blue*k;
return c;
}
 
CRGB operator / (double k, const  CRGB&c1)
{
CRGB c;
c.red = c1.red / k;
c.green = c1.green / k;
c.blue = c1.blue / k;
return c;
}
 
CRGB operator +=(const CRGB &c1, const CRGB &c2)
{
CRGB c;
c.red = c1.red + c2.red;
c.green = c1.green + c2.green;
c.blue = c1.blue + c2.blue;
return c;
}
 
CRGB operator -= (const CRGB &c1, const  CRGB &c2)
{
CRGB c;
c.red = c1.red - c2.red;
c.green = c1.green - c2.green;
c.blue = c1.blue - c2.blue;
return c;
}
 
CRGB operator *= (const CRGB&c1, const  CRGB&c2)
{
CRGB c;
c.red = c1.red * c2.red;
c.green = c1.green * c2.green;
c.blue = c1.blue * c2.blue;
return c;
}
 
CRGB operator /= (const  CRGB&c1, double k)
{
CRGB c;
c.red = c1.red / k;
c.green = c1.green / k;
c.blue = c1.blue / k;
return c;
}
 
void CRGB::Normalize()
{
red = (red<0.0) ? 0.0 : ((red>1.0) ? 1.0 : red);
green = (green<0.0) ? 0.0 : ((green>1.0) ? 1.0 : green);
blue = (blue<0.0) ? 0.0 : ((blue>1.0) ? 1.0 : blue);
}
4、设计Cline直线类
定义直线绘制任意斜率的直线,其成员函数为MoveTo()和LineTo()。
Line.h
#pragma once
#include "P2.h"
#include "RGB.h"
 
class CLine
{
public:
CLine();
virtual ~CLine();
void MoveTo(CDC *, CP2);//移动到指定位置
void MoveTo(CDC *, double, double);
void LineTo(CDC *, CP2);//绘制直线,不含终点
void LineTo(CDC *, double, double);
public:
CP2 P0;//起点
CP2 P1;//终点
};
 
Line.cpp
#include "stdafx.h"
#include "Line.h"
#include "math.h"
#define Round(d) int(floor(d+0.5))//四舍五入宏定义
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif
 
CLine::CLine()
{}
 
CLine::~CLine()
{}
 
void CLine::MoveTo(CDC *pDC, CP2 p0)//绘制直线起点函数
{
P0 = p0;
}
 
void CLine::MoveTo(CDC *pDC, double x0, double y0)//重载函数
{
P0 = CP2(x0, y0);
}
 
void CLine::LineTo(CDC *pDC, CP2 p1)
{
P1 = p1;
CP2 p, t;
CRGB clr = CRGB(0.0, 0.0, 0.0);//黑色像素点
if (fabs(P0.x - P1.x)<1e-6)//绘制垂线
{
if (P0.y>P1.y)//交换顶点,使得起始点低于终点
{
t = P0; P0 = P1; P1 = t;
}
for (p = P0; p.y<P1.y; p.y++)
{
pDC->SetPixelV(Round(p.x), Round(p.y), RGB(clr.red * 255, clr.green * 255, clr.blue * 255));
}
}
else
{
double k, d;
k = (P1.y - P0.y) / (P1.x - P0.x);
if (k>1.0)//绘制k>1
{
if (P0.y > P1.y)
{
t = P0; P0 = P1; P1 = t;
}
d = 1 - 0.5*k;
for (p = P0; p.y < P1.y; p.y++)
{
pDC->SetPixelV(Round(p.x), Round(p.y), RGB(clr.red * 255, clr.green * 255, clr.blue * 255));
if (d >= 0)
{
p.x++;
d += 1 - k;
}
else
d += 1;
}
}
if (0.0 <= k && k <= 1.0)//绘制0<=k<=1
{
if (P0.x > P1.x)
{
t = P0; P0 = P1; P1 = t;
}
d = 0.5 - k;
for (p = P0; p.x < P1.x; p.x++)
{
pDC->SetPixelV(Round(p.x), Round(p.y), RGB(clr.red * 255, clr.green * 255, clr.blue * 255));
if (d < 0)
{
p.y++;
d += 1 - k;
}
else
d -= k;
}
}
if (k >= -1.0 && k<0.0)//绘制-1<=k<0
{
if (P0.x>P1.x)
{
t = P0; P0 = P1; P1 = t;
}
d = -0.5 - k;
for (p = P0; p.x<P1.x; p.x++)
{
pDC->SetPixelV(Round(p.x), Round(p.y), RGB(clr.red * 255, clr.green * 255, clr.blue * 255));
if (d>0)
{
p.y--;
d -= 1 + k;
}
else
d -= k;
}
}
if (k < -1.0)//绘制k<-1
{
if (P0.y<P1.y)
{
t = P0; P0 = P1; P1 = t;
}
d = -1 - 0.5*k;
for (p = P0; p.y>P1.y; p.y--)
{
pDC->SetPixelV(Round(p.x), Round(p.y), RGB(clr.red * 255, clr.green * 255, clr.blue * 255));
if (d < 0)
{
p.x++;
d -= 1 + k;
}
else
d -= 1;
}
}
}
P0 = p1;
}
void CLine::LineTo(CDC *pDC, double x1, double y1)//重载函数
{
LineTo(pDC, CP2(x1, y1));
}
5、添加鼠标消息映射
添加WM_LBUTTONDOWN消息映射函数
void CTestView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO:  在此添加消息处理程序代码和/或调用默认值
 
p0.x = point.x;
p0.y = point.y;
p0.x = p0.x - rect.Width() / 2;                  //设备坐标系向自定义坐标系转换
p0.y = rect.Height() / 2 - p0.y;
 
CView::OnLButtonDown(nFlags, point);
}
添加WM_LBUTTONUP消息映射函数
void CTestView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO:  在此添加消息处理程序代码和/或调用默认值
 
p1.x=point.x;
p1.y=point.y;
CLine *line=new CLine;
CDC *pDC=GetDC();     
//定义设备上下文指针
 
//与案例比新加的语句
GetClientRect(rect);
 
pDC->SetMapMode(MM_ANISOTROPIC);                    //自定义坐标系
pDC->SetWindowExt(rect.Width(),rect.Height());      //设置窗口比例
pDC->SetViewportExt(rect.Width(),-rect.Height());   //设置视区比例,且x轴水平向右,y轴垂直向上
pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);//设置客户区中心为坐标系原点
rect.OffsetRect(-rect.Width()/2,-rect.Height()/2);  //矩形与客户区重合
 
/*pDC->MoveTo(0, 0);
pDC->LineTo(100, 200);*/
 
p1.x=p1.x-rect.Width()/2;
p1.y=rect.Height()/2-p1.y;
line->MoveTo(pDC,p0);
line->LineTo(pDC,p1);
delete line;
ReleaseDC(pDC);
 
CView::OnLButtonUp(nFlags, point);
}
 调试过程及实验结果 
 总 结    本案例实现的Cline类的成员函数类似于CDC类的MoveTo()函数和LineTo()函数,用于绘制任意斜的直线段。MSDN指出CDC类的LineTo()函数画一段直线到终点坐标位置,但不包括终点坐标。CLine类的LineTo()函数实现了该功能。本案例映射了WM_LBUTTONDOWN消息来确定直线段的起点坐标,映射了WM_LBUTTONDOWN消息来确定直线段的终点坐标并绘制直线段。本次实验帮助我更好的了解了图形学的理论知识,锻炼了我的动手能力。
实验地点 指导教师
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: