zoukankan      html  css  js  c++  java
  • 利用canvas实现的中点Bresenham算法

    Bresenham提出的直线生成算法的基本原理是,每次在最大位移方向上走一步,而另一个方向是走步还是不走步取决于误差项的判别,具体的实现过程大家可以去问度娘。我主要是利用canvas画布技术实现了这个过程,算法可能还是有点小问题,欢迎大家给我留言建议,一定虚心接受。

        <!DOCTYPE html>
        <html lang="en">
        <head>
    	<meta charset="UTF-8">
    	<title>中点Bresenham算法</title>
    	<style>
    	    * {
    	    	margin: 0;
    	    	padding: 0;
    	    }
    	    body {
    	        font-family: "Helvetica Neue", Helvetica, Arial, "Microsoft Yahei UI", "Microsoft YaHei", SimHei, "\5B8B\4F53", simsun, sans-serif;
    	        color: #555;
    	    }
    		.left {
    			float: left;
    			margin: 20px 0 0 calc((100% - 401px - 602px)/2);
    			 400px;
    			height: 600px;
    			border: 1px solid #cccccc;
    			border-right: none; 
    		}
    		.left header {
    			margin: 0 10px;
    			-webkit-box-sizing: border-box;
    			-moz-box-sizing: border-box;
    			box-sizing: border-box;
    			height: 60px;
    			line-height: 60px;
    			font-size: 18px;
    			/*text-align: center;*/
    			border-bottom: 2px solid #aaa;
    		}
    		.start {
    			margin: 0 25px;
    			line-height: 80px;
    			/*text-align: center;*/
    		}
    		.left input[type="text"] {
    			padding: 2px 5px;
    			 30px;
    			-webkit-box-sizing: border-box;
    			-moz-box-sizing: border-box;
    			box-sizing: border-box;
    			background-color: #f5f5f5;
    			border: 1px solid #cccccc;
    		}
    		button {
    			border: none;
    			display: inline-block;
    			outline: 0;
    			padding: 6px 16px;
    			margin-bottom: 10px;
    			vertical-align: middle;
    			overflow: hidden;
    			text-decoration: none;
    			color: #fff;
    			background-color: #F88E8B;
    			text-align: center;
    			transition: .2s ease-out;
    			cursor: pointer;
    			white-space: nowrap;
    			box-shadow: 0px 1px 3px rgba(0,0,0,0.12), 0px 1px 2px rgba(0,0,0,0.24);
    		}
    		button:hover {
    			background-color: #F35F5C;
    		}
    		#stroke {
    			margin-left: 25px;
    		}
    		#reset {
    			margin-left: 10px;
    		}
    		/*.left button {
    			display: block;
    			margin: 0 auto;
    		}*/
    		#xy {
    			/*display: none;*/
    		}
    		.left p {
    			line-height: 40px;
    			text-align: center;
    		}
    		.table {
    			position: relative;
    			padding-top: 30px;
    			max-height: 373px;
    			overflow-y: auto;
    			-webkit-box-sizing: border-box;
    			-moz-box-sizing: border-box;
    			box-sizing: border-box;
    		}
    		#thead {
    			position: absolute;
    			z-index: 999;
    			 370px;
    			margin-left: 10px;
    		}
    		.left table {
    			margin: 0 0 10px 10px;
    			 370px;
    			border-collapse:collapse;
    		}
    		.left table th{
    			 33.3333%;
    			height: 30px;
    			border: 1px solid #cccccc;
    			background-color: #f1f1f1;
    		}
    		.left table td{
    			 33.3333%;
    			height: 30px;
    			text-align: center;
    			border: 1px solid #cccccc;
    		}
    		#myCanvas {
    			display: block;
    			float: left;
    			margin-top: 20px;
    			background-color: #fffdf6;
    			border: 1px solid #cccccc;
    		}
    	</style>
        </head>
        <body>
    	<div class="left" id="left">
    		<header>&nbsp;&nbsp;中点 <strong>Bresenham</strong> 算法</header>
    		<div class="start">
    			直线方程 : 
    			<input type="text" id="A" required autocomplete="off"> x + <input type="text" id="B" required autocomplete="off"> y + <input type="text" id="C" required autocomplete="off"> = 0
    		</div>
    		<button id="stroke">开始绘制</button>
    		<button id="reset">重置</button>
    		
    		<div id="xy" style="display: none;">
    			<p><strong>坐标值</strong></p>
    			<table id="thead">
    				<tr>
    					<th> X </th>
    					<th> Y </th>
    					<th> d </th>
    				</tr>
    			</table>
    			<div class="table">
    				<table id="table">
    					<!-- <tr>
    						<th> X </th>
    						<th> Y </th>
    						<th> d </th>
    					</tr> -->
    				</table>
    			</div>
    		</div>
    		
    	</div>
    	<canvas id="myCanvas" width="600" height="600">
    		您的浏览器不支持canvas,请升级浏览器!
    	</canvas>
    
    	<script>
    
    		//*-----------------canvas画坐标表格---------------------*
    		var canvas=document.getElementById("myCanvas");
    		var context=canvas.getContext("2d");
    
    		function drowAxes() {
    			// 描绘边框
    			var grid_cols = 20;
    			var grid_rows = 20;
    			var cell_height = canvas.height / grid_rows;
    			var cell_width = canvas.width / grid_cols;
    			context.lineWidth = 1;
    			context.strokeStyle = "#cccccc";
    
    			// 结束边框描绘
    			context.beginPath();
    			// 准备画横线
    			for (var col = 1; col <= grid_cols; col++) {
    			  var x = col * cell_width;
    			  if(col == 10) {
    			  	context.beginPath();
    			  	context.strokeStyle = "#2FB9D6";
    			  	context.moveTo(x+0.5,0);
    			  	context.lineTo(x+0.5,canvas.height);
    			  	context.stroke();
    			  }
    			  else {
    			  	context.beginPath();
    			  	context.strokeStyle = "#cccccc";
    			  	context.moveTo(x+0.5,0);
    			  	context.lineTo(x+0.5,canvas.height);
    			  	context.stroke();
    			  }
    			}
    			//准备画竖线
    			for(var row = 1; row <= grid_rows; row++){
    			  var y = row * cell_height;
    			  if(row == 10) {
    			  	context.beginPath();
    			  	context.strokeStyle = "#2FB9D6";
    			  	context.moveTo(0,y+0.5);
    			  	context.lineTo(canvas.width, y+0.5);
    			  	context.stroke();
    			  }
    			  else {
    			  	context.beginPath();
    			  	context.strokeStyle = "#cccccc";
    			  	context.moveTo(0,y+0.5);
    			    context.lineTo(canvas.width, y+0.5);
    			  	context.stroke();
    			  }
    			}
    			context.stroke();
    
    			//给坐标轴加刻度
    			for(var i=0;i <= grid_cols;i++) {
    				var x = i * cell_width;
    				context.font="13px Arial";
    				context.fillStyle="#000";
    				context.fillText(-10+i,5 + x,315);
    			}
    			for(var i=0;i <= grid_rows;i++) {
    				var y = i * cell_height;
    				context.font="13px Arial";
    				context.fillStyle="#000";
    				context.fillText(10-i,305,15 + y);
    			}
    		}
    
    		//坐标生成及Canvas画点函数
    		function drawDot(x,y,d) {
    			var tr=document.createElement("tr");
    			var td1=document.createElement("td");
    			var node1=document.createTextNode(" "+Math.round(x)+" ");
    			td1.appendChild(node1);
    			tr.appendChild(td1);
    
    			var td2=document.createElement("td");
    			var node2=document.createTextNode(" "+Math.round(y)+" ");
    			td2.appendChild(node2);
    			tr.appendChild(td2);
    
    			var td3=document.createElement("td");
    			var node3=document.createTextNode(" "+d.toFixed(2)+" ");
    			td3.appendChild(node3);
    			tr.appendChild(td3);
    
    			document.getElementById("table").appendChild(tr);
    
    			//坐标处理
    			var X,Y;
    			X= Math.round(x)*30;
    			Y=- Math.round(y)*30;
    			//表格中绘制坐标点
    			context.fillStyle="#2FB9D6";
    			context.beginPath();
    			context.arc(X,Y,4,0,Math.PI*2,true);
    			context.closePath();
    			context.fill();
    		}
    	    
    	    //判断输入的字符是否为整数    
    	    function IsInteger()     
    	    {       
    	            var str1 = document.getElementById('A').value.trim();    
    	            var str2 = document.getElementById('B').value.trim();    
    	            var str3 = document.getElementById('C').value.trim();    
    	            if(str1.length!=0 && str2.length!=0 && str3.length!=0){    
    		            reg=/^[-+]?\d*$/;     
    		            if(!reg.test(str1) || !reg.test(str2) || !reg.test(str3)){    
    		                alert("对不起,请输入整数!");//请将“整数类型”要换成你要验证的那个属性名称! 
    		                return false;   
    		            } 
    		            else {return true;}   
    	            }    
    	    } 
    
    		window.onload = drowAxes();
    		var canvas_flag=0;//设置是否画线的标记变量
    
    		//*-----------------中点Bresenham算法求坐标--------------------*
    		document.getElementById("stroke").onclick=function Bresenham(){
    			var xy=document.getElementById("xy");
    
    			var A=document.getElementById("A").value;
    			var B=document.getElementById("B").value;
    			var C=document.getElementById("C").value;
    
    			if(A.length == 0 || B.length == 0 || C.length == 0) {alert("请填写直线方程的系数!")}
    			//直线上取两个点
    			if(xy.style.display === 'none' && A.length != 0 && B.length != 0 && C.length != 0 && IsInteger()) {
    				if(A==0 && B==0 && C!=0) {alert("输入错误,请重新输入!");}
    				else if(A==0 && B==0 && C==0) {alert("输入数据不能全部为0!")}
    				else if(A==0 && B!=0) { //y=c 类方程
    					context.translate(300,300);//将坐标原点移到(300,300)处
    					
    					//绘制直线
    					var c=-Math.round(C/B)*30;
    					context.beginPath();
    					context.strokeStyle="#2FB9D6";
    					context.moveTo(-300,c);
    					context.lineTo(300,c);
    					context.closePath();
    					context.stroke();
    
    					canvas_flag=1;//标记变量置1
    
    				}
    				else if(A!=0 && B==0) { //x=c 类方程
    					context.translate(300,300);//将坐标原点移到(300,300)处
    					
    					//绘制直线
    					var c=-Math.round(C/A)*30;
    					context.beginPath();
    					context.strokeStyle="#2FB9D6";
    					context.moveTo(c,-300);
    					context.lineTo(c,300);
    					context.closePath();
    					context.stroke();
    
    					canvas_flag=1;//标记变量置1
    
    				}
    				else if(-A/B>=0){  //斜率大于等于0的情况
    					xy.style.display = 'block';
    					var x0,y0,x1,y1;
    					var vx,vy;
    					var d; //增长量
    					var m,n; //循环变量
    					var x,y;
    
    					var k = -A/B;
    					if(k>=0 && k<=1) { //k大于等于0小于等于1的情况
    						x0 = -5;x1 = 5;
    						y0 = (-C -A*x0)/B;
    						y1 = (-C -A*x1)/B;
    						vx = x1 - x0,vy = y1 - y0;
    						x = x0,y = y0;
    						n = x0;
    						m = x1;
    						d = vx - 2*vy; //初始化d
    					}
    					else if(k>1) { //k大于1的情况 
    						y0 = -5;y1 = 5;
    						x0 = (-C -B*y0)/A;
    						x1 = (-C -B*y1)/A;
    						vx = x1 - x0,vy = y1 - y0;
    						x = x0,y = y0;
    						n = y0;
    						m = y1;
    						d = 2*vx - vy; //初始化d
    					}
    					context.translate(300,300);//将坐标原点移到(300,300)处
    					for(var i=n;i<=m;i++) {
    
    						//----------------算法核心代码---------------
    						if(k>=0 && k<=1) { //k大于等于0小于等于1的情况
    							drawDot(x,y,d);
    							if(d<0) {
    								x = x + 1;
    								y = y + 1;
    								d = d + 2*vx - 2*vy;
    							}
    							else {
    								x = x + 1;
    								y = y;
    								d = d - 2*vy;
    							}
    						}
    						else if(k>1) { //k大于1的情况
    							drawDot(x,y,d);
    							if(d<0) {
    								x = x;
    								y = y + 1;
    								d = d + 2*vx;
    							}
    							else {
    								x = x + 1;
    								y = y + 1;
    								d = d - 2*vy + 2*vx;
    							} 
    						}
    						
    					}
    					//绘制直线
    					var X0,Y0,X1,Y1;
    					X0= Math.round(x0)*30;
    					Y0=-Math.round(y0)*30;
    					X1=Math.round(x1)*30;
    					Y1=-Math.round(y1)*30;
    					context.beginPath();
    					context.strokeStyle="#2FB9D6";
    					context.moveTo(X0,Y0);
    					context.lineTo(X1,Y1);
    					context.closePath();
    					context.stroke();
    
    					canvas_flag=1;//标记变量置1
    				}
    				else if(-A/B<0){ //斜率小于0的情况
    					//将直线转化为斜率大于等于0的情况,然后求关于x轴对称的直线就行
    					xy.style.display = 'block';
    					A = -A; 
    					var x0,y0,x1,y1;
    					var vx,vy;
    					var d; //增长量
    					var m,n; //循环变量
    					var x,y;
    
    					var k = -A/B;
    					if(k>=0 && k<=1) { //k大于等于0小于等于1的情况
    						x0 = -5;x1 = 5;
    						y0 = (-C -A*x0)/B;
    						y1 = (-C -A*x1)/B;
    						vx = x1 - x0,vy = y1 - y0;
    						x = x0,y = y0;
    						n = x0;
    						m = x1;
    						d = vx - 2*vy; //初始化d
    					}
    					else if(k>1) { //k大于1的情况 
    						y0 = -5;y1 = 5;
    						x0 = (-C -B*y0)/A;
    						x1 = (-C -B*y1)/A;
    						vx = x1 - x0,vy = y1 - y0;
    						x = x0,y = y0;
    						n = y0;
    						m = y1;
    						d = 2*vx - vy; //初始化d
    					}
    					context.translate(300,300);//将坐标原点移到(300,300)处
    					for(var i=n;i<=m;i++) {
    
    						//----------------算法核心代码---------------
    						if(k>=0 && k<=1) { //k大于等于0小于等于1的情况
    							drawDot(-x,y,d);
    							if(d<0) {
    								x = x + 1;
    								y = y + 1;
    								d = d + 2*vx - 2*vy;
    							}
    							else {
    								x = x + 1;
    								y = y;
    								d = d - 2*vy;
    							}
    						}
    						else if(k>1) { //k大于1的情况
    							drawDot(-x,y,d);
    							if(d<0) {
    								x = x;
    								y = y + 1;
    								d = d + 2*vx;
    							}
    							else {
    								x = x + 1;
    								y = y + 1;
    								d = d - 2*vy + 2*vx;
    							} 
    						}
    						
    					}
    					//绘制直线
    					var X0,Y0,X1,Y1;
    					X0= Math.round(-x0)*30;
    					Y0=-Math.round(y0)*30;
    					X1=Math.round(-x1)*30;
    					Y1=-Math.round(y1)*30;
    					context.beginPath();
    					context.strokeStyle="#2FB9D6";
    					context.moveTo(X0,Y0);
    					context.lineTo(X1,Y1);
    					context.closePath();
    					context.stroke();
    
    					canvas_flag=1;//标记变量置1
    				}
    			}
    			
    		};
    
    		//重新绘制
    		document.getElementById("reset").onclick=function reset(){
    
    			var A=document.getElementById("A").value;
    			var B=document.getElementById("B").value;
    			var C=document.getElementById("C").value;
    			if(A.length == 0 && B.length == 0 && C.length == 0) {alert("没有输入数据!")}
    			else {
    				//清空input输入框
    				document.getElementById("A").value="";
    				document.getElementById("B").value="";
    				document.getElementById("C").value="";
    			}
    			if(canvas_flag==1) {
    				context.clearRect(-300,-300,600,600); //清空画布
    				context.translate(-300,-300); //将坐标原点还原
    				drowAxes(); //重绘坐标轴
    
    				canvas_flag=0;
    			}
    			if(document.getElementById("xy").style.display === 'block') {
    				document.getElementById("xy").style.display = 'none';
    
    				var table = document.getElementById("table");
    			    while(table.hasChildNodes()) //当table下还存在子节点时 循环继续
    			    {
    			        table.removeChild(table.firstChild);
    			    }
    			}
    		};
    
    	    </script> 
            </body>
            </html>
    
  • 相关阅读:
    加快网站访问速度——Yslow极限优化
    Jquery应用实例
    js获取文本框(或文本域)光标位置以及设置光标位置
    编程挑战
    图片view设置gif动图
    判断手机中是否安装了某个App
    session发送的get请求、post请求、上传、下载
    图片的拉伸stretchableImageWithLeftCapWidth
    IOS数据懒加载
    IOS页面(控制器之间)传值之Block
  • 原文地址:https://www.cnblogs.com/sunmaer/p/6014121.html
Copyright © 2011-2022 走看看