码迷,mamicode.com
首页 > 编程语言 > 详细

画直线算法 Line drawing algorithm

时间:2021-05-04 16:06:08      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:ati   set   swa   增加   cout   超出   根据   水平   结果   

Line drawing algorithm 罗列了几种在屏幕像素上画直线的算法。

不过如果让我自己想的话,思维过程应该是这样:

  1. 算法的输入?两个实数点。

  2. 算法的输出?若干个自然数点。

  3. 怎么展示算法结果?屏幕上的像素可以抽象成一个二维数组,点作为坐标索引来定位,给二维数组赋值相当于给像素上色。

  4. 过程?

    直线可以分为:水平的(斜率为零)、垂直的(斜率为无穷大),斜的(其他可能的斜率)。

    给定两个实数点,可以算出一个实数域上的直线方程。但显然此方程的解不能直接作为算法的解,它还需要再通过一个函数过滤成自然数的解。

    real = line_equation(p1, p2)
    nature = func(real)
    

    最直接的想法是每次迭代我都算出实数解,然后和上一个自然数解作比较。e.g. 当 x0 < x1, y0 < y1 时,和当前像素的 y 比较,大于半个像素时说明实数解远了,所以不该继续画在 y 上了,应该画在 y + 1 上。

    x0 < x1, y0 < y1 
    
    function line(x0, y0, x1, y1) 
        real slope := (y1 - y0 / x1 - x0)
        real realxy:= y0
        int y := y0
        for x from x0 to x1 
            realy := realy + slope
            if realy - y ≥ 0.5 then
                 y := y + 1
         plot(x, y)
    

    当然根据斜率不同还有一些符号和边界问题,暂且不表。值得注意的是,因为 realy >= y + 0.5 所以 y+1 之后是可能比 realy 大的,但是大不过 0.5 。下次再算 realy 的时候,还可能比 y 小。不过也没关系,我们就继续画在 y 上就行。

Bresenham‘s line algorithm

计算的是每一像素点与该线之间的误差。误差应为每一点x中,其相对的像素点之y值与该线实际之y值的差距。每当x的值增加1,误差的值就会增加slope。每当误差的值超出0.5,线就会比较靠近下一个映像点,因此y的值便会加1,且误差减1。

x0 < x1, y0 < y1 

function line(x0, y0, x1, y1)
    real deltax := x1 - x0
    real deltay := y1 - y0
    real deltaerr := deltay / deltax
    real error := 0.0 // No error at start
    int y := y0
    for x from x0 to x1 
        plot(x, y)
        error := error + deltaerr
        if error ≥ 0.5 then
            y := y + 1
            error := error - 1.0

我的代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int width = 20;
const int height = 20;
const char clear_char = ‘ ‘;
const char mark_char = ‘*‘;

char screen[width][height];

struct point 
{ 
    int x, y; 
    point(int _x, int _y) : x(_x), y(_y) {}
};

struct testcase
{
    point p1, p2;
    void (*func_draw_line)(point&, point&);

    testcase(point _p1, point _p2, void (*func)(point&, point&)) : p1(_p1), p2(_p2), func_draw_line(func) {}

    void run() { func_draw_line(p1, p2); }
};

void show_screen()
{
    for (int i = 0; i < width; ++i) cout << ‘=‘;
    cout << endl;
    for (int i = width - 1; i >= 0; --i)
    {
        for (int j = 0; j < height; ++j)
            cout << screen[i][j];
        cout << endl;
    }
}


void native(point& p1, point& p2)
{
    memset(screen, clear_char, sizeof(screen));

    // horizontal line
    if (p1.y == p2.y)
    {
        int dx = p1.x < p2.x ? 1 : -1;
        for (int x = p1.x; x != p2.x; x += dx)
            screen[x][p1.y] = mark_char;
    }
    // vertical line
    else if (p1.x == p2.x)
    {
        int dy = p1.y < p2.y ? 1 : -1;
        for (int y = p1.y; y != p2.y; y += dy)
            screen[p1.x][y] = mark_char;
    }
    // slanted line
    else
    {
        double slope = static_cast<double>(p1.x - p2.x) / (p1.y - p2.y);
        int dx = slope > 0 ? 1 : -1;

        int starty = p1.y;
        int endy = p2.y;
        double realx = p1.x;
        if (p1.y > p2.y)
        {
            swap(starty, endy);
            realx = p2.x;
        }
        int x = realx;
        for (int y = starty; y <= endy; ++y)
        {
            screen[x][y] = mark_char;
            realx += slope;
            if (abs(realx - x) > 0.5) x = x + dx;
        }
    }
    show_screen();
}

int main()
{
    testcase tcs[] = 
    {
        { point(2, 3), point(2, 10), native },
        { point(11, 5), point(1, 5), native },
        { point(1, 1), point(8, 6), native },
        { point(3, 1), point(5, 16), native },
        { point(10, 1), point(1, 17), native },
    };

    for (testcase& t : tcs) t.run();

    return 0;
}

画直线算法 Line drawing algorithm

标签:ati   set   swa   增加   cout   超出   根据   水平   结果   

原文地址:https://www.cnblogs.com/tandandan/p/14725697.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!