Breshenham画线算法及应用

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 <GL/glut.h>
#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 <GL/glut.h>
#include <cmath>
#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 <GL/glut.h>
#include "Graphics.h"

//45-90度的圆弧的斜率k是-1<k<0,x+1,比较y是-0或-1.
//P(0) = 1 - r
//P(k) < 0; P(k+1) = P(k) + 2x(k+1) + 1
//P(k) > 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 <GL/glut.h>
#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);
}

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值