Breshenham画线算法是由Bresenham提出的一种精确而有效的光栅线生成算法,该算法仅仅使用增量整数计算。
原理:当斜率小于 1 时,x 增加 1, y 增加 0 或 1.因此只需要判断 y 是增加 0 或 1.
算法:画线段(x0, y0)到(xEnd, yEnd), 线性方程 y = mx + b
假设已经确定要显示的像素在(x_k, y_k), 那么下一步需要确定在列x_(k+1) = x_k + 1 上绘制哪个像素,是在位置(x_k + 1, y_k),还是(x_k + 1, y_k + 1)。
y = m(x_k + 1) + b, y 离上下两个像素的偏量
d_lower = y - y_k
d_upper = (y_k+1) - y
d_lower - d_upper = y - y_k - ( y_k + 1 - y )
= 2*y - 2*y_k - 1
= 2*m(x_k + 1) + 2b - 2*y_k - 1 // y = mx + b
m = dy/dx // 0 < m < 1
设P_k = dx*(d_lower - d_upper) //若P_k小于 0, 则 y 离 y_k 更近, 下一个像素取(x_k+1, y_k), 反之亦然。
= 2*dy*x_k - 2*dx*y_k + c | c = 2*dy - 2*b*dx - dx
P_(k+1) = 2*dy*(x_k+1) - 2*dx*y_(k+1) + c // 当x_k+1时,y_k可能加 0 或 1, 所以 y_(k+1) - y_k 可能为 0 或 1
P_(k+1) - P_k = 2*dy - 2*dx*( y_(k+1) - y_k )
P_(k+1) = P_k + 2*dy - 2*dx*( y_(k+1) - y_k ) // 这样根据上一个P可以求出下一个P,只要知道P0就可以求出所有的P
P0是x_k = x0是的P值,此时y_k = y0 = m*x0 + b, 根据上面P_k的式子可以求出P0
P0 = 2*dy*x0 - 2*dx*y0 + 2*dy - 2*b*dx - dx
= 2*dy*x0 - 2*dx*(m*x0 + b) + 2*dy - 2*b*x0 + b
= 2*dy - dx
当P_k < 0 时, y_(k+1) - y_k = 0, P_(k+1) = P_k + 2*dy
当P_k > 0 时, y_(k+1) - y_k = 1, P_(k+1) = P_k + 2*dy - 2*dx
头文件
#ifndef GRAPHICS_H
#define GRAPHICS_H
//共用函数
void setPixel(int x, int y);
int intRound(float a);
//线段
void line(int x1, int y1, int x2, int y2);
//圆
void circle(int xc, int yc, int r);
//椭圆
void ellipse(int xCenter, int yCenter, int x, int y);
#endif
公用函数
#include
#include "Graphics.h"
void setPixel(int x, int y)
{
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
}
int intRound(float a)
{
return int(a + 0.5);
}
线段
#include
#include
#include "Graphics.h"
void ResetTwoPoints(int& x1, int& y1, int& x2, int &y2)
{
int temp;
if (x2 < x1) {
temp = x1;
x1 = x2;
x2 = temp;
temp = y1;
y1 = y2;
y2 = temp;
}
}
//0 < k < 1
//P(0) = 2dy - dx
//P(k) < 0; P(k+1) = P(k) + 2dy
//P(k) > 0; P(k+1) = P(k) + 2dy - 2dx
void line(int x1, int y1, int x2, int y2)
{
ResetTwoPoints(x1, y1, x2, y2); //让x2 > x1, 便于计算
int x = x1, y = y1;
int dy = y2 - y1, dx = x2 - x1;
int p;
float k;
if (x1 == x2 || y1 == y2 || abs(dx) == abs(dy)) {
//当线段平行或垂直xy轴时,可以用DDA算法进行整数计算
int incrementx, incrementy, step;
if (abs(dx) >= abs(dy))
step = abs(dx);
else
step = abs(dy);
incrementx = dx / step;
incrementy = dy / step;
setPixel(x, y);
for (int k = 0; k < step; k++) {
x += incrementx;
y += incrementy;
setPixel(x, y);
}
}else {
float k = float(dy) / float(dx);
if (fabs(k) < 1) {
p = 2 * abs(dy) - dx;
setPixel(x, y);
while (x < x2) {
x++;
if (p < 0)
p += 2 * abs(dy);
else {
if (dy > 0) //判断y是增加还是减少
y++;
else
y--;
p += 2 * abs(dy) - 2 * dx;
}
setPixel(x, y);
}
}else {
ResetTwoPoints(y1, x1, y2, x2); //k>1时,交换x和y
p = 2 * abs(dx) - dy;
setPixel(x, y);
while (y < y2) {
y++;
if (p < 0)
p += 2 * abs(dx);
else {
if (dx > 0) //判断x是增加还是减少
x++;
else
x--;
p += 2 * abs(dx) - 2 * dy;
}
setPixel(x, y);
}
}
}
}
圆
#include
#include "Graphics.h"
//45-90度的圆弧的斜率k是-1 0; P(k+1) = P(k) + 2x(k+1) + 1 - 2y(k+1)
void circle(int xc, int yc, int r)
{
void circlePlotPoints(int x, int y, int xc, int yc);
int x = 0, y = r;
int p = 1 - r;
circlePlotPoints(x, y, xc, yc);
while (x <= y) {
x++;
if (p < 0) {
p += 2 * x + 1;
}else {
y++;
p += 2 * x + 1 - 2 * y;
}
circlePlotPoints(x, y, xc, yc);
}
}
void circlePlotPoints(int x, int y, int xc, int yc)
{
setPixel(xc + x, yc + y);
setPixel(xc - x-1, yc + y);
setPixel(xc + x, yc - y-1);
setPixel(xc - x-1, yc - y-1);
setPixel(xc + y, yc + x);
setPixel(xc - y-1, yc + x);
setPixel(xc + y, yc - x-1);
setPixel(xc - y-1, yc - x-1);
}
椭圆
#include
#include "Graphics.h"
//同圆一样
//region 1
//2Ry*Ry*x >= 2Rx*Rx*y
//P(0) = Ry*Ry + 0.25Rx*Rx - Rx*Rx*Ry
//P(k) < 0; P(k+1) = P(k) + 2*Ry*Ry*x(k+1) + Ry*Ry
//P(k) > 0; P(k+1) = P(k) + 2*Ry*Ry*x(k+1) + Ry*Ry - 2Rx*Rx*y(k+1)
//region 2
//2Ry*Ry*x < 2Rx*Rx*y
//P(0) = Rx*Rx + 0.25*Ry*Ry - Rx*Ry*Ry
//P(k) < 0; P(k+1) = P(k) + 2*Rx*Rx*y(k+1) + Rx*Rx
//P(k) > 0; P(k+1) = p(k) + 2*Rx*Rx*y(k+1) + Rx*Rx + 2Ry*Ry*x(k+1)
void ellipse(int xCenter, int yCenter, int Rx, int Ry)
{
int Rx2 = Rx * Rx;
int Ry2 = Ry * Ry;
int twoRx2 = 2 * Rx2;
int twoRy2 = 2 * Ry2;
int p;
int x = 0;
int y = Ry;
int px = 0;
int py = twoRx2 * y;
void ellipsePlotPoints(int, int, int, int);
ellipseMidpoint(xCenter, yCenter, x, y);
p = intRound(Ry2 - (Rx2*Ry) + float(0.25*Rx2));
while(px < py){
x++;
px += twoRy2;
if (p < 0)
p += Ry2 + px;
else {
y--;
py -= twoRx2;
p += Ry2 + px - py;
}
ellipsePlotPoints(xCenter, yCenter, x, y);
}
x = Rx; y = 0;
px = twoRy2 * x; py = 0;
ellipseMidpoint(xCenter, yCenter, x, y);
p = intRound(Rx2 + 0.25*Ry2 - Rx * Ry2);
while (px > py) {
y--;
py += twoRx2;
if (p < 0)
p += Rx2 + py;
else {
x--;
px -= twoRy2;
p += Rx2 + py - px;
}
ellipsePlotPoints(xCenter, yCenter, x, y);
}
}
void ellipsePlotPoints(int xCenter, int yCenter, int x, int y)
{
setPixel(xCenter + x, yCenter + y);
setPixel(xCenter - x, yCenter + y);
setPixel(xCenter + x, yCenter - y);
setPixel(xCenter - x, yCenter - y);
}