第一天上班,遇到难题了,用C实现DrawLine函数,高手进~~~

cocat 2010-11-11 10:06:01
第一天上班,告诉我用纯C实现个类似DrawLine(int x1, int y1, int x2, int y2)这样的函数,很重要的一点是得实现平台无关性,就是在啥平台下都能用,不能跟系统函数关联,哎~我只会用这个东西,要我实现真的是碰到大问题了~

然后还有重要的一点是:我不是简简单单要实现直线的算法,还得考虑后面那些比如改变线宽度、虚线、反走样、抗锯齿结合起来,就是得规划清楚,比如先调用改变宽度,再DrawLine这样画出来的是想改变宽度的直线。

我不懂我说的请不清楚,反正就是得用纯C来实现各种画线(实线、虚线、不同宽度线...),像弄成个小型的图像库,给别人调用,比较底层的东西。

有做过或者高手给点思路或者参考代码~最好有什么demo~谢谢了~

...全文
2130 117 打赏 收藏 转发到动态 举报
写回复
用AI写文章
117 条回复
切换为时间正序
请发表友善的回复…
发表回复
lzero13199 2011-05-24
  • 打赏
  • 举报
回复
同情你,,,,,
justinkine 2011-01-01
  • 打赏
  • 举报
回复
sdl啊!很好的一个跨平台的媒体库!还可以实现更加牛逼的东西!
cshboom 2010-12-31
  • 打赏
  • 举报
回复
这是逛csdn遇见的最长贴。果断mark。学习之。
青蛙果果 2010-12-31
  • 打赏
  • 举报
回复
应该只是考算法的吧
BRESENHAM
cocat 2010-12-31
  • 打赏
  • 举报
回复
谢谢大家的回复了~方法我想了很多,但是由于我要弄得这个东西是个大项目的一小部分,个人写的东西根本达不到效率~用了cairo(linux平台下的)这个库和自己写的东西相结合,基本还是实现了功能~那些库的移植还是上头弄得~呵呵~谢谢大家的热心回复~
Perrolass 2010-12-31
  • 打赏
  • 举报
回复
建议楼主去看看AGG的代码 核心内容是多边形填充 任何图形都转化为多边形来绘画 核心算法在rasterizer_cells_aa这个类中


典型的宽直线,拆为4条线;圆,拆为N条线段;等等。
job82824 2010-12-30
  • 打赏
  • 举报
回复
Qt可以的,跨平台只要重新编译一下就行了
dieyingao 2010-12-30
  • 打赏
  • 举报
回复
这道题目应该是考那个什么画线算法的吧
nilite 2010-12-30
  • 打赏
  • 举报
回复
挺容易的。布兰森汉姆算法画就可以了。



/*用Bresenham算法画一条线(不检查参数,自定义颜色)
//==================================================================
//函数名: draw_line()
//日期: 2008-12-16
//输入参数:(x1, y1):画线的起始座标
(x2, y2):画线的结束座标
DISP_MODE_PUT: 直接设置
DISP_MODE_OR: 与屏幕原有值“或取”后再写
DISP_MODE_XOR: 与屏幕原有值“异或”后再写
DISP_MODE_AND: 与屏幕原有值“与取”后再写
draw_dot:画点函数
color:点的颜色(也可以替换成别的参数)
//返回值: 成功返回0,
失败返回<0
//注意事项:1、无。
//=================================================================*/
int draw_line(int x0, int y0, int x1, int y1,
int (*draw_dot)(int x, int y, unsigned char color),
unsigned char color)
{
if ((x0 == x1) && (y0 == y1))
{
return *draw_dot(x0, y0, color);
}

int dx,dy; //定义X.Y轴上增加的变量值
int sub;
int retval;

dx = abs(x1 - x0); //X轴方向上的增量
dy = abs(y1 - y0); //Y轴方向上的增量

/* 布兰森汉姆(Bresenham)算法画线 */
if (dx > dy) //靠近X轴
{
sub = 2 * dy - dx; //计算下个点的位置
while (x0 != x1)
{
retval = *draw_dot(x0, y0, color); //画起点
if (retval < 0)
{
return retval;
}
if (x1 > x0)
{
x0++;
}
else
{
x0--; //X轴上加1
}
if (sub > 0) //判断下下个点的位置
{
if (y1 > y0)
{
y0++;
}
else
{
y0--; //为右上相邻点,即(x0+1,y0+1)
}
sub += (2 * dy) - (2 * dx);
}
else
{
sub += 2 * dy; //判断下下个点的位置
}
}
retval = *draw_dot(x0, y0, color);;
if (retval < 0)
{
return retval;
}
}
else
{
sub = 2 * dx - dy; //靠近Y轴
while (y0 != y1)
{
retval = *draw_dot(x0, y0, color); //画起点
if (retval < 0)
{
return retval;
}
if (y1 > y0)
{
y0++;
}
else
{
y0--;
}
if (sub > 0) //判断下下个点的位置
{
if (x1 > x0)
{
x0++;
}
else
{
x0--;
}
sub += (2 * dx) - (2 * dy);
}
else
{
sub += 2 * dx;
}
}
retval = *draw_dot(x0, y0, color);
if (retval < 0)
{
return retval;
}
}
return 0;
}
lengxujun 2010-12-30
  • 打赏
  • 举报
回复
前面掉了一个函数实现:


static unsigned char far *get_video_buf(void)
{
return Graph_device_cntx.vdo_buf;
}
PenGHNet 2010-12-30
  • 打赏
  • 举报
回复
这样你可以只着重于画线,估计你上面也是这样要求的吧。
PenGHNet 2010-12-30
  • 打赏
  • 举报
回复
我想应当这样做这件事:定义一个内在块,内在的分配是各系统都有的AllocMem(),这是各操作系统都有的系统函数,假想这就是显示屏,在这个上面画线。画好好,将期调用于显示设备的空间,这个可以用宏定义区分,如调用win可以直接操作系统提供的图形函数。
Ferrerox 2010-12-30
  • 打赏
  • 举报
回复
[Quote=引用 59 楼 yashuwa0622cvte 的回复:]

直接用printf(".")连成线
[/Quote]
只有这句话我看懂了~~~
lengxujun 2010-12-30
  • 打赏
  • 举报
回复
不好意思,第一次提交以为没成功(没注意到跑到第2页来了),所以多提交一次.
lengxujun 2010-12-30
  • 打赏
  • 举报
回复
写个Turbo C简单实现.


#include <stdio.h>
#include <dos.h>
#include <math.h>
#include <assert.h>

#define VIDEO_BUF_ADDR 0xA0000000L /* 0xA0000,破16bit的短指针,转换一下 */
#define EMPTY_COLOR (-1) /* 非法的颜色值 */

#define SWAP(a, b) do { a ^= b; b ^= a; a ^= b; } while (0)
#define NUM_ELEM(a) (sizeof(a)/sizeof((a)[0]))

typedef struct _video_attribute
{
video_mode_t vdo_mode;
u32_t max_color;
int scrn_w, scrn_h; /* screen resolution: width x height */
} video_attr_t, p_video_attr_t;

typedef struct _graph_device_context
{
video_attr_t * vdo_attr_p;
unsigned char far * vdo_buf;
color_t bg_color;
color_t fg_color;
} graph_device_cntx_t;

static graph_device_cntx_t Graph_device_cntx;

static video_attr_t Video_attrs[] =
{
{VIDEO_MODE_VGA256, 256, 320, 200},
{VIDEO_MODE_TEXT, 0, 0, 0 }
};

static unsigned char far *get_video_buf(void);

void init_graph(void)
{
Graph_device_cntx.vdo_attr_p = NULL;
Graph_device_cntx.vdo_buf = (unsigned char far *)VIDEO_BUF_ADDR;
Graph_device_cntx.bg_color = EMPTY_COLOR;
Graph_device_cntx.fg_color = EMPTY_COLOR;
}

int set_video_mode(video_mode_t vdo_mode)
{
union REGS in_reg, out_reg;
int i;

assert(vdo_mode >= 0 && vdo_mode != VIDEO_MODE_NONE);

for (i = 0; i < NUM_ELEM(Video_attrs); i++)
{
if (Video_attrs[i].vdo_mode == vdo_mode)
{
Graph_device_cntx.vdo_attr_p = &Video_attrs[i];
break;
}
}

assert(i < NUM_ELEM(Video_attrs));

in_reg.h.ah = 0;
in_reg.h.al = (unsigned char)vdo_mode;
int86(0x10, &in_reg, &out_reg);

return 1;
}

int get_scrn_width(void)
{
return Graph_device_cntx.vdo_attr_p->scrn_w;
}

void set_bg_color(color_t c)
{
unsigned char far *vdo_buf = get_video_buf();
int x, y, scrn_w, scrn_h;

Graph_device_cntx.bg_color = c;

x = 0;
y = 0;
scrn_w = get_scrn_width();
scrn_h = get_scrn_height();

for (x = 0; x < scrn_w; x++)
for (y = 0; y < scrn_h; y++)
vdo_buf[y*scrn_w+x] = c;
}

unsigned long get_max_color(void)
{
return Graph_device_cntx.vdo_attr_p->max_color;
}

void gui_put_pixel_ex(int x, int y, color_t c)
{
unsigned char far *vdo_buf = get_video_buf();

assert(0 <= c && c <= get_max_color());
vdo_buf[y * get_scrn_width() + x] = c;
}

void gui_bresenham_draw_line_ex(int x1, int y1, int x2, int y2, color_t c)
{
int b_steep = abs(y2 - y1) > abs(x2 - x1);
int dx, dy;
int error;
int x, y, y_step;

/* if abs(slope) > 1, swap x and y coordinates */
if (b_steep)
{
SWAP(x1, y1);
SWAP(x2, y2);
}

/* if draw line direction from right to left, reverse it */
if (x1 > x2)
{
SWAP(x1, x2);
SWAP(y1, y2);
}

dx = x2 - x1;
dy = abs(y2 - y1);
error = dx >> 1; /* dx / 2 */
y = y1;

/* determinate the inc in y-axis direction */
if (y1 < y2)
y_step = 1;
else
y_step = -1;

for (x = x1; x <= x2; x++)
{
if (b_steep)
gui_put_pixel_ex(y, x, c);
else
gui_put_pixel_ex(x, y, c);

error -= dy;

if (error < 0)
{
y += y_step;
error += dx;
}
}
}

/* 调用 */
#include <conio.h> /* 借用enum COLORS颜色值 */

int main(void)
{
init_graph();

set_video_mode(VIDEO_MODE_VGA256);

set_bg_color(255);

gui_bresenham_draw_line_ex(200, 20, 14, 143, LIGHTMAGENTA);
gui_bresenham_draw_line_ex(17, 14, 234, 156, RED);

getch();
set_video_mode(VIDEO_MODE_TEXT);

return 0;
}


未处理线宽调整等.
lengxujun 2010-12-30
  • 打赏
  • 举报
回复
我也给个Turbo C 2.0下的简单实现


/*
* 平台相关代码
*/

#define WIN32 /* 当然Turbo C 2.0下没有WIN32这个宏, 为运行为Turbo C 2.0定义的函数,定义它 */

#ifdef WIN32

#define VIDEO_BUF_ADDR 0xA0000000L /* 0xA0000 */
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 200

typedef enum _video_mode_tag
{
VIDEO_MODE_VGA256 = 0x13,
VIDEO_MODE_TEXT = 0x03,
VIDEO_MODE_NONE
} video_mode_t;

/* 函数set_video_mode(), set_bg_color()与平台有关,各个平台可能都要实现 */

void set_video_mode(int mode)
{
union REGS inregs, outregs;

inregs.h.ah = 0;
inregs.h.al = (unsigned char)mode;
int86(0x10, &inregs, &outregs);
}

void set_bg_color(color_t c)
{
unsigned char far *vdo_buf = VIDEO_BUF_ADDR;
int x, y, scrn_w, scrn_h;

x = 0;
y = 0;
scrn_w = SCREEN_WIDTH;
scrn_h = SCREEN_HEIGHT;

for (x = 0; x < scrn_w; x++)
for (y = 0; y < scrn_h; y++)
vdo_buf[y * scrn_w + x] = c;
}

void gui_put_pixel_ex(int x, int y, color_t c)
{
unsigned char far *vdo_buf = VIDEO_BUF_ADDR;

vdo_buf[y * SCREEN_WIDTH + x] = c;
}

#elif defined(UNIX)

void gui_put_pixel_ex(int x, int y, color_t c)
{
/* unix 平台画点实现 */
}

#elif /* 其他平台 */

void gui_put_pixel_ex(int x, int y, color_t c)
{
/* 其他平台画点实现函数 */
}

#endif


/*
* 平台无关代码
*/

/* 交换a和b的值 */
typedef long color_t;

#define SWAP(a, b) do { a ^= b; b ^= a; a ^= b; } while (0)

void gui_bresenham_draw_line_ex(int x1, int y1, int x2, int y2, color_t c)
{
int b_steep = abs(y2 - y1) > abs(x2 - x1);
int dx, dy;
int error;
int x, y, y_step;

/* if abs(slope) > 1, swap x and y coordinates */
if (b_steep)
{
SWAP(x1, y1);
SWAP(x2, y2);
}

/* if draw line direction from right to left, reverse it */
if (x1 > x2)
{
SWAP(x1, x2);
SWAP(y1, y2);
}

dx = x2 - x1;
dy = abs(y2 - y1);
error = dx >> 1; /* dx / 2 */
y = y1;

/* determinate the inc in y-axis direction */
if (y1 < y2)
y_step = 1;
else
y_step = -1;

for (x = x1; x <= x2; x++)
{
if (b_steep)
gui_put_pixel_ex(y, x, c);
else
gui_put_pixel_ex(x, y, c);

error -= dy;

if (error < 0)
{
y += y_step;
error += dx;
}
}
}


/*
* 使用
*/
#include <conio.h>

int main(void)
{
/* 设置视频模式为VGA 256色 */
set_video_mode(VIDEO_MODE_VGA256);

/* 设置背景色为白色 */
set_bg_color(255);

/* 画线: 借用conio.h中的枚举值enum COLORS(实际的颜色值为[0, 255]) */
gui_bresenham_draw_line_ex(200, 20, 14, 143, LIGHTMAGENTA);
gui_bresenham_draw_line_ex(17, 14, 234, 156, RED);

getch();
set_video_mode(VIDEO_MODE_TEXT); /* 恢复视频模式为文本模式 */

return 0;
}


上面的代码没有处理线宽,反锯齿等.
preciousboy 2010-12-30
  • 打赏
  • 举报
回复
opencv是可以的,里面有相关的函数;如果自己实现就找找画线的算法,网上有,我以前也下载过,LZ现在完成了吗
Defonds 2010-12-26
  • 打赏
  • 举报
回复
有难度
  • 打赏
  • 举报
回复
看到楼主都快升星了,俺这些不懂菜鸟只能来帮顶了
希望楼主早日搞定
freeway 2010-12-25
  • 打赏
  • 举报
回复
与平台无关,楼主有没有看过FATFS之类的系统?将驱动留给别人自己填充,好比基本的画点驱动交给移植的人去做,只管把画线的方法抽象出来。
加载更多回复(85)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧