如何画直线,看起来似乎很简单,拿个直线方程,遍历X求出Y,再把对应点画出来不就行了么,嘿嘿,没那么简单~
平时我们所说的直线是在实数域的,也就是说对应的Y可能是小数,而在屏幕上,所画直线是基于正整数域的,那么根据直线方程如何画直线呢?
先考虑斜率 0 < k < 1的情况
1.Bresenham算法
该算法由Bresenham在1965年发明,它到底做了什么事呢?其实想法很简单,就是每X移动一个像素,则考虑Y应该是如何移动。
由于由(x0,y0),(x1,y1)两点构成的直线方程为:
y-y0 = (y1-y0)/(x1-x0) * (x-x0)
对于每一点的x值其y为:
(y1-y0)/(x1-x0) * (x-x0) + y0
可见并非每一点x对应的y都为整数,所以没有必要去计算每一点x对应的y值,只需求出哪一点的x值导致y值+1,如果x尚未到此值,则这中间的x对应的y都不变。
如何找到这个值则要依靠直线方程斜率k,x每增加1个单位,y值都增加k个单位,而每一个x的像素点都对应一个误差,为直线中根据x求得的y与x的像素点y的差,如果误差绝对值>0.5则表示其靠近下一个像素点的y,此时把y+1,误差值-1。
2.伪代码
drawline(x0,y0,x1,y1)
{
int dx = x1 - x0;
int dy = y1 - y0;
float k = (float)dy / dx;
float error = 0;
for(int x = x0,y = y0:x <= x1; ++x)
{
draw(x,y);
error += k;
if(fabs(error) >= 0.5)
{
y += 1;
error -= 1;
}
}
}
3.在linux终端窗口中画直线
主要思想:
构造一个二维字符数组,以空格为其基本元素,以此在屏幕形成画布
若要画点则将对应点赋值'*',画完后刷新画布,可见图形
4.具体实现
CCanvas类接口:
CCanvas(int width = 40,int height = 40); //构造函数,形成一定大小的画布
Init(); //完成画布初始化工作
void SetValue(int x,int y,char c); //在(x,y)处"画"一个点
void Refresh(); //刷新显示画布
//CCanvas.h
#include <vector>
class CCanvas
{
public:
CCanvas(int width = 40,int height = 40);
~CCanvas();
void SetValue(int x,int y,char c);
typedef std::vector<std::vector<char> >::iterator ITER;
private:
int m_width,m_height;
std::vector<std::vector<char> > m_info;
void Init();
};
//CCanvas.cpp
#include <iostream>
#include "CCanvas.h"
CCanvas::CCanvas(int width,int height)
{
m_width = width;
m_height = height;
Init();
}
CCanvas::~CCanvas()
{
}
void CCanvas::Init()
{
m_info.resize(m_height);
for(ITER it = m_info.begin();it != m_info.end(); ++it)
{
it->resize(m_width,' ');
}
void CCanvas::SetValue(int x,int y,char c)
{
if(x >= m_width || y >= m_height)
{
printf("bad args!");
return;
}
m_info[y][x] = c;
}
void CCanvas::Refresh()
{
for(int i = 0;i != m_height; ++i)
{
for(int j = 0;j != m_width; ++j)
{
printf("%c",m_info[i][j]);
}
printf("/n");
}
}
//主文件
#include <iostream>
#include <cmath>
#include "CCanvas.h"
CCanvas g_canvas;
void DrawLine(int x0,int y0,int x1,int y1)
{
int dx = x1 - x0;
int dy = y1 - y0;
float k = (float)dy / dx;
float error = 0;
for(int x = x0,y = y0:x <= x1; ++x)
{
draw(x,y);
error += k;
if(fabs(error) >= 0.5)
{
y += 1;
error -= 1;
}
}
}
int main()
{
std::cout << "please enter the startpoint (x0,y0) and endpoint (x1,y1)..." << std::endl;
int x0,y0,x1,y1;
std::cin >> x0 >> y0 >> x1 >> y1;
DrawLine(x0,y0,x1,y1);
g_canvas.Refresh();
return 0;
}
为了便于调试写一个Makefile文件
Makefile
objects = CCanvas.o DrawLine.o
DrawLine : $(objects)
g++ -g $(objects) -o DrawLine
DrawLine.o : DrawLine.cpp CCanvas.h
g++ -g -c CCanvas.h DrawLine.cpp
CCanvas.o : CCanvas.h
g++ -g -c CCanvas.h CCanvas.cpp
.PHONY : clean
clean :
-rm DrawLine $(objects)
//编译 运行
make
./DrawLine
如何在窗口中画直线
最新推荐文章于 2022-04-17 23:16:42 发布