直线中点Bresenham算法

课程名称

计算机图形学

班级

 

实验日期

 

姓名

 

学号

 

实验成绩

 

实验名称

直线中点Bresenham算法

斜率0≤k≤1直线的中点Bresenham算法。

任意斜率直线段绘制算法。

颜色类的定义与调用方法。

直线类的定义与调用方法。

鼠标按键消息映射方法。

 

 

1、案例描述

在屏幕客户区内按下鼠标左键赞扬直线的起点,移动鼠标指针到直线终点上,弹起鼠标左键绘制任意斜率的直线段。

2、功能说明

1)设计CRGB类其成员变量为double型的红绿蓝分量red,greenblue,将red,greenblue分量分别规范到[0,1]区间。

2)设计Cline直线类,其成员变量为直线段的起点坐标P0和终点坐标P1,成员函数为MoveTo()LineTo()函数。

3Cline类的LineTo()函数使用中点Bresenham算法绘制任意斜率的直线段,包括k=±∞,k>1,0≤�≤1, -1≤�<0k<-15种情况

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

3x=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消息来确定直线段的终点坐标并绘制直线段。本次实验帮助我更好的了解了图形学的理论知识,锻炼了我的动手能力。

实验地点

 

指导教师

猜你喜欢

转载自blog.csdn.net/qq_37606901/article/details/79553047