- 寫在開頭:
相關實驗是學校開設課程的相關實驗,本人所作較為粗淺,若有同校師弟浏覽,望看懂借鑒而非照搬全抄。
- 實驗目的:
了解Bresenham畫線算法
- 實驗内容:
用Bresenham畫線算法實作水準、垂直、斜率大于1、斜率小于1、斜率為正、斜率為負等各種情況(不能直接調用OpenGL畫線函數)。
- 實作效果及步驟(或流程)
實作效果:
繪制了一個大小為40 × 40 網格圖(坐标為0~39),用以模拟螢幕像素。以(20,20)為中心,繪制了六條“直線”。這些“直線”模拟了當螢幕像素點被放大至肉眼可見時,Bresenham算法繪制直線時的繪制情況。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL0EkaOJzaU90MNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLzcTM2QzNyYTMwETMwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
實作流程:
首先判斷斜率是否小于1,如果是則計算p值(p=2dy –dx),而後選擇起點并繪制起點;接着判斷斜率正負,如果為正,則x遞增1,通過p值判斷y值,并且計算相應的p值,否則x遞減1。
如果斜率大于1,則将求p值公式x、y互換,并且将x遞增或遞減的變化過程改為y遞增或遞減。
具體流程見下圖。
- 創新設計和實作方法
創新設計:
使用正方形塊模拟螢幕像素點,繪制螢幕網格圖,展示Bresenham算法選點的過程。
實作方法:
1.網格的繪制:
設定矩形塊為線性填充,使用二維數組blocks[40][40]存儲矩形塊,取blocks[x][y],即代表取螢幕坐标(x,y)。
相關代碼如下:
void initBlocks() {
glPolygonMode(GL_FRONT, GL_LINE);
GLint x = 0, y = 0;
glColor3f(0.0, 0.0, 1.0);
//初始化矩形塊坐标
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++) {
blocks[i][j].point[0] = x;
blocks[i][j].point[1] = y;
y += 10;
}
y = 0;
x += 10;
}
//繪制矩形
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++) {
glRecti(blocks[i][j].point[0], blocks[i][j].point[1],
blocks[i][j].point[0] + 10, blocks[i][j].point[1] + 10);
}
}
glFlush();
}
2.繪制“像素點”
如果需要繪制點(x,y),那麼繪制矩形塊blocks[x][y]即可。
相關代碼如下:
//選取像素塊
void setPixel(GLint x, GLint y) {
glPolygonMode(GL_FRONT, GL_FILL);//設定矩形為填充模式
glColor3f(0.0, 1.0, 0.0);
glRecti(blocks[x][y].point[0], blocks[x][y].point[1],
blocks[x][y].point[0] + 10, blocks[x][y].point[1] + 10);
glFlush();
}
- 源代碼
#include <GL/glut.h>
#include <iostream>
void bresenham(GLint x1, GLint y1, GLint x2, GLint y2);
GLsizei winWidth = 400, winHeight = 400;
//“像素塊”
struct block {
GLint point[2];
};
block blocks[40][40];
//初始化像素塊
void initBlocks() {
glPolygonMode(GL_FRONT, GL_LINE);
GLint x = 0, y = 0;
glColor3f(0.0, 0.0, 1.0);
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++) {
blocks[i][j].point[0] = x;
blocks[i][j].point[1] = y;
y += 10;
}
y = 0;
x += 10;
}
for (int i = 0; i < 40; i++) {
for (int j = 0; j < 40; j++) {
glRecti(blocks[i][j].point[0], blocks[i][j].point[1],
blocks[i][j].point[0] + 10, blocks[i][j].point[1] + 10);
}
}
//調試用
//for (int i = 0; i < 40; i++) {
// for (int j = 0; j < 40; j++) {
// std::cout << i << "," <<j <<" (" << blocks[i][j].point[0] << ","
// << blocks[i][j].point[1] << ")" << " ";
// }
// std::cout << std::endl;
//}
glFlush();
}
//選取像素塊
void setPixel(GLint x, GLint y) {
//glBegin(GL_POINTS);
// glVertex2i(x, y);
//glEnd();
glPolygonMode(GL_FRONT, GL_FILL);
glColor3f(0.0, 1.0, 0.0);
std::cout << "(" << blocks[x][y].point[0] << "," << blocks[x][y].point[1] << ")" << " ";
glRecti(blocks[x][y].point[0], blocks[x][y].point[1],
blocks[x][y].point[0] + 10, blocks[x][y].point[1] + 10);
glFlush();
}
void init(void) {
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, 200.0, 0.0, 150.0);
}
void displayFcn() {
initBlocks();
glColor3f(0.0, 1.0, 0.0);
bresenham(5,20,35,20);//水準線段
bresenham(20,5,20,35);//垂直線段
bresenham(5, 13, 35, 27);//斜率介于0到1之間的直線
bresenham(5, 27, 35, 13);//斜率介于-1到0之間的直線
bresenham(13, 35, 27, 5);//斜率小于-1的直線
bresenham(27, 35, 13, 5);//斜率大于-1的直線
}
void bresenham(GLint x1, GLint y1, GLint x2, GLint y2) {
GLint dx_sigend = x1 - x2, dy_sigend = y1 - y2;
GLint dx = fabs(dx_sigend), dy = fabs(dy_sigend);
GLint twoDy = 2 * dy, twoDx = 2 * dx;
GLint twoDyMinusDx = 2 * (dy - dx),twoDxMinusDy = 2 * (dx - dy);
GLint p;
GLint x, y;
// 判斷斜率是否大于1
if (dy < dx) {
p = twoDy - dx;
//判斷斜率正負
if ((dx_sigend < 0 && dy_sigend < 0) || (dx_sigend > 0 && dy_sigend > 0)) {
//判斷所給點的起點
if (x1 > x2) {
x = x2;
y = y2;
x2 = x1;
}
else {
x = x1;
y = y1;
}
setPixel(x, y);
while (x < x2) {
x++;
if (p < 0) {
p += twoDy;
}
else {
++y;
p += twoDyMinusDx;
}
setPixel(x, y);
}
}
else {
//判斷所給點的起點
if (x1 < x2) {
x = x2;
y = y2;
x2 = x1;
}
else {
x = x1;
y = y1;
}
setPixel(x, y);
while (x > x2) {
x--;
if (p < 0) {
p += twoDy;
}
else {
++y;
p += twoDyMinusDx;
}
setPixel(x, y);
}
}
}
else {
p = twoDx - dy;
//判斷斜率正負
if ((dx_sigend < 0 && dy_sigend < 0) || (dx_sigend > 0 && dy_sigend > 0)) {
//判斷所給點的起點
if (y1 > y2) {
x = x2;
y = y2;
y2 = y1;
}
else {
x = x1;
y = y1;
}
setPixel(x, y);
while (y < y2) {
y++;
if (p < 0) {
p += twoDx;
}
else {
++x;
p += twoDxMinusDy;
}
setPixel(x, y);
}
}
else {
//判斷所給點的起點
if (y1 < y2) {
x = x2;
y = y2;
y2 = y1;
}
else {
x = x1;
y = y1;
}
setPixel(x, y);
while (y > y2) {
y--;
if (p < 0) {
p += twoDx;
}
else {
++x;
p += twoDxMinusDy;
}
setPixel(x, y);
}
}
}
}
void winReshapeFcn(GLint newWidth, GLint newHeight) {
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, newWidth, newHeight);
glLoadIdentity();
gluOrtho2D(0.0, GLdouble(newWidth), 0.0, GLdouble(newHeight));
winWidth = newWidth;
winHeight = newHeight;
}
void main(int argc, char ** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(100, 100);
glutInitWindowSize(winWidth, winHeight);
glutCreateWindow("CGLab3_CaiYiPei");
init();
glutDisplayFunc(displayFcn);
glutReshapeFunc(winReshapeFcn);
glutMainLoop();
}