接着上一篇的 计算实现给出屏幕上任意两个点,求出这两个点之间直线上的所有的点。http://www.cnblogs.com/sepeng/p/4042464.html 这种直接算法的确是被鄙视了
强大的度娘告诉我们还有专用的算法叫bresenham算法。调用我大脑中所有的数学知识残留借用网上资料,费尽了吃奶的力气才把这个算法推导了一遍,高手们不要笑话
后来觉得这个时候讨论的是 0<k<1.那么把pi换一换就是 -1<k<0.仿真后发现自己又脑残了一次,对算法知之甚少,组合了好几次都没有组合成功,最后不得不把-1<k<0的算法拿出来讨论
这次才知道-1<k<0的时候 pi,xi 长啥样子,我的大脑还是猜不出来的,老老实实的推导算法吧。
算法推导出来了,这下好了就开始写FPGA的实现了
1 /* 2 date:2014/10/22 3 version : QuartusII + de1-soc cyclone V 4 designer : pengxiaoen 5 funtion : 实现bresenham 算法在象限对直线的计算 6 |k| <1 任意方向都满足 7 */ 8 9 module bresenham ( 10 clock , 11 reset , 12 xs_in , //输入的X 点的起始坐标 13 ys_in , // 输入的Y 点的起始坐标 14 xe_in , //输入X点的终止坐标 15 ye_in , //输入Y 点的终止坐标 16 in_en , //当前输入信号有效标志 1:有效 0:无效 17 18 x_ou, //输出的X 点的坐标 19 y_ou, // 输出的Y 点的坐标 20 fini_flag //计算完成标志位 21 ); 22 input clock ,reset ; 23 input in_en ; 24 input [9:0] xs_in ,xe_in ; 25 input [8:0] ys_in ,ye_in ; 26 27 output reg [9:0] x_ou ; 28 output reg [8:0] y_ou ; 29 output reg fini_flag ; 30 31 wire [15:0] dx ; // X方向上的变化量 32 wire [15:0] dy ; //Y方向上的变化量 33 reg signed [15:0] pi ; 34 wire x_dir ; 35 wire y_dir ; 36 37 wire [9:0] Xmin ; 38 wire [9:0] Xmax ; 39 wire [8:0] Ymin ; 40 wire [8:0] Ymax ; 41 // 42 assign x_dir= (xs_in<xe_in)? 1'd0 : 1'd1 ; 43 assign y_dir= (ys_in<ye_in)? 1'd0 : 1'd1 ; 44 assign Xmin = (xs_in<xe_in)? xs_in : xe_in ; 45 assign Xmax = (xs_in<xe_in)? xe_in : xs_in ; 46 assign Ymin = (ys_in<ye_in)? ys_in : ye_in ; 47 assign Ymax = (ys_in<ye_in)? ye_in : ys_in ; 48 49 assign dx = Xmax-Xmin; //得出X方向上的差值 50 assign dy = Ymax-Ymin; //得出Y方向上的差值 51 52 reg signed [9:0] x_cnt ; // X 坐标计数 有符号运算 53 //********************************************************** 54 always @ (posedge clock ) 55 if(!reset) 56 begin 57 x_cnt <= 10'd0 ; 58 fini_flag <= 1'd0 ; 59 end 60 else if(in_en) //数据装载 61 begin 62 x_cnt <= xs_in ; 63 fini_flag <= 1'd0 ; 64 end 65 else if (x_cnt==xe_in) // 运算完毕 66 begin 67 //x_cnt <= 10'd0 ; 68 fini_flag <= 1'd1 ; 69 end 70 else //运算进行中 71 begin 72 x_cnt <= x_cnt + {{9{x_dir}},1'd1}; 73 fini_flag <= 1'd0 ; 74 end 75 76 77 always @(posedge clock ) 78 if(!reset) 79 begin 80 y_ou <= 9'd0 ; 81 x_ou <= 10'd0 ; 82 end 83 else if ((!fini_flag) && (!in_en)) //运算标志正在运算,并且装载数据完成 84 begin 85 if(pi[15]) 86 begin 87 pi <= pi+(dy<<1) ; 88 x_ou <= x_cnt ; 89 end 90 else 91 begin 92 pi <= pi + (dy<<1) - (dx<<1) ; 93 y_ou <= y_ou + {{8{y_dir}},1'd1}; 94 x_ou <= x_cnt ; 95 end 96 end 97 else 98 begin 99 pi <= (dy<<1)-dx ; 100 y_ou <= ys_in ; 101 x_ou <= xs_in ; 102 end 103 104 endmodule
附上测试代码
1 `timescale 1ns/1ps 2 3 4 module bresenham_tb ; 5 6 reg clock ,reset ; 7 reg in_en ; 8 reg [9:0] xs_in ,xe_in ; 9 reg [8:0] ys_in ,ye_in ; 10 11 wire [9:0] x_ou ; 12 wire [8:0] y_ou ; 13 wire fini_flag ; 14 15 16 bresenham U1_bresenham( 17 .clock (clock), 18 .reset (reset), 19 .xs_in (xs_in), 20 .ys_in (ys_in), 21 .xe_in (xe_in), 22 .ye_in (ye_in), 23 .in_en (in_en), 24 25 .x_ou (x_ou), 26 .y_ou (y_ou), 27 .fini_flag (fini_flag) 28 ); 29 30 31 always #10 clock = ~clock ; 32 33 initial 34 begin 35 clock = 1'd0 ; reset =1'd0 ; in_en = 1'd0 ; 36 xs_in = 10'd0 ; xe_in = 10'd0 ; 37 ys_in = 9'd0 ; ye_in = 9'd0 ; 38 39 #40 reset = 1 ; 40 in_en = 1 ; 41 xs_in = 100 ; xe_in = 200 ; 42 ys_in = 100 ; ye_in = 150 ; 43 #80 in_en = 0 ; 44 #3000 ; // k = 1/2 验证 正方向 45 46 in_en = 1 ; 47 xs_in = 200 ; xe_in = 100; 48 ys_in = 150 ; ye_in = 100; 49 #80 in_en = 0 ; 50 #3000 ; // k = 1/2 验证 反方向 51 52 in_en = 1 ; 53 xs_in = 100 ; xe_in= 200 ; 54 ys_in = 100 ; ye_in= 50 ; 55 #80 in_en = 0 ; // k = -1/2 验证 正方向 56 #3000 57 58 in_en = 1 ; 59 xs_in = 200 ; xe_in= 100; 60 ys_in = 50 ; ye_in= 100 ; 61 #80 in_en = 0 ; // k = -1/2 验证 反方向 62 #3000 63 64 65 $stop ; 66 67 end 68 69 endmodule