计算机图形学中直线连接算法的Javascript实现

之前在想如何使用Javascript实现时钟的时候,被一个问题难到了:如何在像素级别绘制平滑的直线。

在网上查了一下,后来在图书馆里的一本关于计算机图形学的老书里发现了解决方案。针对这个问题,书上提供了三个算法,分别是简单DDA,对称DDA,Bresenham算法。

下面的是我使用简单DDA和Bresenham算法在浏览器上绘制Hello world的代码。

这里的Hello world 分别是定义了字母的一些”节点“,然后使用连线算法绘制出来的。

代码:

  1. //构造画布,使用DOM动态生成表格
  2. var _container = document.getElementById("container");
  3. var pixs = new Array();
  4. var canvasTbody = document.createElement("tbody");
  5. var bgColor = "black";
  6. var fontColor = "green";
  7. var pix_size = "4px";
  8. var pix_numbs = 81;
  9. var temp_tr ;
  10. var temp_td ;
  11. var temp_pixrow;
  12. for(var i = pix_numbs; i >= 0 ; i--){
  13.     temp_tr = document.createElement("tr");
  14.     temp_tr.style.height = pix_size;
  15.     temp_pixrow = new Array();
  16.     for(var j = 0; j <= pix_numbs ; j++){
  17.         temp_td = document.createElement("td");
  18.         temp_td.style.width=pix_size;
  19.         temp_td.style.backgroundColor = bgColor;
  20.         temp_tr.appendChild(temp_td);
  21.         temp_pixrow[j] = temp_td;
  22.     }
  23.     canvasTbody.appendChild(temp_tr);
  24.     pixs[i] = temp_pixrow;
  25. }
  26. var canvasTable = document.createElement("table");
  27. canvasTable.style.backgroundColor = "black";
  28. canvasTable.setAttribute("cellspacing","0");
  29. canvasTable.setAttribute("cellpadding","0");
  30. canvasTable.appendChild(canvasTbody);
  31. _container.appendChild(canvasTable);
  32. // 点 类,包含坐标信息,有绘制和比较操作
  33. function point(_x,_y){
  34.     this.x = _x;
  35.     this.y = _y;
  36. }
  37. function _draw(){
  38.     if(this.x > pix_numbs || this.y > pix_numbs){
  39.         return;
  40.     }
  41.     pixs[this.y][this.x].style.backgroundColor = fontColor;
  42. }
  43. point.prototype.draw = _draw;
  44. function _equal(_p){
  45.     if(! _p instanceof point){
  46.         throw new Error();
  47.     }
  48.     if(this.x == _p.x && this.y == _p.y){
  49.         return true;
  50.     }else{
  51.         return false;
  52.     }
  53. }
  54. point.prototype.equal = _equal;
  55. //简单DDA算法构造直线
  56. function DDA_line(_p1,_p2){
  57.     var x1;
  58.     var y1;
  59.     var x2;
  60.     var y2;
  61.     var _x;
  62.     var _y;
  63.     var _p;
  64.     var k;
  65.     var b;
  66.     
  67.     
  68.     if(_p1 instanceof point && _p2 instanceof point){
  69.     }else{
  70.         return ;
  71.     }
  72.     
  73.     if(_p1.equal(_p2)){
  74.         return ;
  75.     }
  76.     
  77.     
  78.     if(_p1.x > _p2.x){
  79.         x1 = _p2.x;
  80.         y1 = _p2.y;
  81.         x2 = _p1.x;
  82.         y2 = _p1.y;
  83.     }else if(_p1.x < _p2.x){
  84.         x1 = _p1.x;
  85.         y1 = _p1.y;
  86.         x2 = _p2.x;
  87.         y2 = _p2.y;
  88.     }else if(_p1.x == _p2.x){
  89.         if(_p1.y > _p2.y){
  90.             x1 = _p2.x;
  91.             y1 = _p2.y;
  92.             x2 = _p1.x;
  93.             y2 = _p1.y;
  94.         }else{
  95.             x1 = _p1.x;
  96.             y1 = _p1.y;
  97.             x2 = _p2.x;
  98.             y2 = _p2.y;
  99.         }
  100.     }
  101.     
  102.     
  103.     if(x1 == x2){
  104.         _x = x1;
  105.         _y = y1;
  106.         for(;_y != y2;_y++){
  107.             _p = new point(_x,_y);
  108.             _p.draw();
  109.         }
  110.     }else{
  111.         k = (y2 - y1)/(x2 - x1);
  112.         b = y1-(k*x1);
  113.         if(Math.abs(k) <= 1){
  114.         _x = x1;
  115.             for(;_x != x2;_x++){
  116.                 _y = (k*_x) +b;
  117.                 _y = Math.round(_y);
  118.                 _p = new point(_x,_y);
  119.                 _p.draw();
  120.             }
  121.         }else{
  122.             _y = y1;
  123.             while(_y != y2){
  124.                 _x = (_y-b)/k;
  125.                 _x = Math.round(_x);
  126.                 _p = new point(_x,_y);
  127.                 _p.draw();
  128.                 if(y2 > y1){
  129.                     _y++;
  130.                 }else{
  131.                     _y--;
  132.                 }
  133.             }
  134.         }
  135.     }
  136. }
  137. //Bresenham算法构造直线
  138. function Bresenham_line(_p1,_p2){
  139.     var x1;
  140.     var y1;
  141.     var x2;
  142.     var y2;
  143.     var _x;
  144.     var _y;
  145.     var _p;
  146.     var k;
  147.     var d;
  148.     if(_p1 instanceof point && _p2 instanceof point){
  149.     }else{
  150.         return ;
  151.     }
  152.     
  153.     if(_p1.equal(_p2)){
  154.         return ;
  155.     }
  156.     
  157.         if(_p1.x > _p2.x){
  158.         x1 = _p2.x;
  159.         y1 = _p2.y;
  160.         x2 = _p1.x;
  161.         y2 = _p1.y;
  162.     }else if(_p1.x < _p2.x){
  163.         x1 = _p1.x;
  164.         y1 = _p1.y;
  165.         x2 = _p2.x;
  166.         y2 = _p2.y;
  167.     }else if(_p1.x == _p2.x){
  168.         if(_p1.y > _p2.y){
  169.             x1 = _p2.x;
  170.             y1 = _p2.y;
  171.             x2 = _p1.x;
  172.             y2 = _p1.y;
  173.         }else{
  174.             x1 = _p1.x;
  175.             y1 = _p1.y;
  176.             x2 = _p2.x;
  177.             y2 = _p2.y;
  178.         }
  179.     }
  180.     
  181.     if(x1 == x2){
  182.         _x = x1;
  183.         _y = y1;
  184.         for(;_y != y2;_y++){
  185.             _p = new point(_x,_y);
  186.             _p.draw();
  187.         }
  188.     }else{
  189.         k = (y2 - y1)/(x2 - x1);
  190.         _x = x1;
  191.         _y = y1;
  192.         if(k >= 0 && k <= 1){
  193.             d = 2*(y2 - y1) - (x2 - x1);
  194.             while(_x != x2){
  195.                 if(d >= 0){
  196.                     _y++;
  197.                     d = d - 2*(x2 - x1);
  198.                 }
  199.                 _p = new point(_x,_y);
  200.                 _p.draw();
  201.                 _x++;
  202.                 d = d + 2*(y2 - y1);
  203.             }
  204.         }else if(k > 1){
  205.             d = 2*(x2 - x1) - (y2 - y1);
  206.             while(_y != y2){
  207.                 if(d >= 0){
  208.                     _x++;
  209.                     d = d - 2*(y2 - y1); 
  210.                 }
  211.                 _p = new point(_x,_y);
  212.                 _p.draw();
  213.                 _y++;
  214.                 d = d + 2*(x2 - x1);
  215.             }
  216.         }else if(k < 0 && k >= -1){
  217.             d = 2*(y2 - y1) +(x2 - x1);
  218.             while(_x != x2){
  219.                 if(d <= 0){
  220.                     _y--;
  221.                     d = d + 2*(x2 - x1);
  222.                 }
  223.                 _p = new point(_x,_y);
  224.                 _p.draw();
  225.                 _x++;
  226.                 d = d + 2*(y2 - y1);
  227.             }
  228.         }else if(k < -1){
  229.             d = 2*(x2 - x1) + (y2 - y1);
  230.             while(_y != y2){
  231.                 if(d >= 0){
  232.                     _x++;
  233.                     d = d - 2*(y1 - y2);
  234.                 }
  235.                 _p = new point(_x,_y);
  236.                 _p.draw();
  237.                 _y--;
  238.                 d = d + 2*(x2 - x1);
  239.             }
  240.         }
  241.     }
  242.     
  243. }
  244. //绘制X
  245. var x1 = new point(5,60);
  246. x1.draw();
  247. var x2 = new point(77,60);
  248. x2.draw();
  249. var x3 = new point(5,25);
  250. x3.draw();
  251. var x4 = new point(77,25);
  252. x4.draw();
  253. Bresenham_line(x1,x4);
  254. Bresenham_line(x2,x3);
  255. //绘制HELLO WORLD
  256. var p1 = new point(5,20);
  257. p1.draw();
  258. var p2 = new point(5,15);
  259. p2.draw();
  260. var p3 = new point(5,10);
  261. p3.draw();
  262. var p4 = new point(10,20);
  263. p4.draw();
  264. var p5 = new point(10,15);
  265. p5.draw();
  266. var p6 = new point(10,10);
  267. p6.draw();
  268. DDA_line(p1,p3);
  269. DDA_line(p2,p5);
  270. DDA_line(p4,p6);
  271. p1 = new point(12,20);
  272. p1.draw();
  273. p2 = new point(12,15);
  274. p2.draw();
  275. p3 = new point(12,10);
  276. p3.draw();
  277. p4 = new point(17,20);
  278. p4.draw();
  279. p5 = new point(17,15);
  280. p5.draw();
  281. p6 = new point(17,10);
  282. p6.draw();
  283. DDA_line(p1,p3);
  284. DDA_line(p1,p4);
  285. DDA_line(p2,p5);
  286. DDA_line(p3,p6);
  287. p1 = new point(19,20);
  288. p1.draw();
  289. p2 = new point(19,10);
  290. p2.draw();
  291. p3 = new point(24,10);
  292. p3.draw();
  293. DDA_line(p1,p2);
  294. DDA_line(p2,p3);
  295. p1 = new point(26,20);
  296. p1.draw();
  297. p2 = new point(26,10);
  298. p2.draw();
  299. p3 = new point(31,10);
  300. p3.draw();
  301. DDA_line(p1,p2);
  302. DDA_line(p2,p3);
  303. p1 = new point(33,20);
  304. p1.draw();
  305. p2 = new point(33,10);
  306. p2.draw();
  307. p3 = new point(38,20);
  308. p3.draw();
  309. p4 = new point(38,10);
  310. p4.draw();
  311. DDA_line(p1,p2);
  312. DDA_line(p3,p4);
  313. DDA_line(p1,p3);
  314. DDA_line(p2,p4);
  315. p1 = new point(45,20);
  316. p1.draw();
  317. p2 = new point(45,10);
  318. p2.draw();
  319. p3 = new point(47,15);
  320. p3.draw();
  321. p4 = new point(49,10);
  322. p4.draw();
  323. p5 = new point(49,20);
  324. p5.draw();
  325. DDA_line(p1,p2);
  326. DDA_line(p2,p3);
  327. DDA_line(p3,p4);
  328. DDA_line(p4,p5);
  329. p1 = new point(51,20);
  330. p1.draw();
  331. p2 = new point(51,10);
  332. p2.draw();
  333. p3 = new point(56,20);
  334. p3.draw();
  335. p4 = new point(56,10);
  336. p4.draw();
  337. DDA_line(p1,p2);
  338. DDA_line(p3,p4);
  339. DDA_line(p1,p3);
  340. DDA_line(p2,p4);
  341. p1 = new point(58,20);
  342. p1.draw();
  343. p2 = new point(58,16);
  344. p2.draw();
  345. p3 = new point(58,10);
  346. p3.draw();
  347. p4 = new point(63,20);
  348. p4.draw();
  349. p5 = new point(63,16);
  350. p5.draw();
  351. p6 = new point(63,10);
  352. p6.draw();
  353. DDA_line(p1,p3);
  354. DDA_line(p1,p4);
  355. DDA_line(p4,p5);
  356. DDA_line(p2,p5);
  357. DDA_line(p2,p6);
  358. p1 = new point(65,20);
  359. p1.draw();
  360. p2 = new point(65,10);
  361. p2.draw();
  362. p3 = new point(70,10);
  363. p3.draw();
  364. DDA_line(p1,p2);
  365. DDA_line(p2,p3);
  366. p1 = new point(72,20);
  367. p1.draw();
  368. p2 = new point(72,10);
  369. p2.draw();
  370. p3 = new point(77,20);
  371. p3.draw();
  372. p4 = new point(77,14);
  373. p4.draw();
  374. DDA_line(p1,p2);
  375. DDA_line(p3,p4);
  376. DDA_line(p1,p3);
  377. DDA_line(p2,p4);

使用方法是在网页中建一个id为”container“的容器,可以是”div“标签

然后把Javascript文件链接进来。即可。

说明:在IE中测试时,有点丑陋。是因为我不知道在IE中使用Javascript动态生成的tbody标签中的单元格之间的间距如何控制。

其他浏览器均可以正常显示。

你可能感兴趣的:(JavaScript,算法,浏览器,function,table,图形)