Code clipping algorithm for line segment

Keywords: Javascript Algorithm Math

Code clipping algorithm for line segment

For example, many uneven straight-line segments are distributed on a canvas, and we want to find a rectangular window on the canvas and only want to get the straight-line segments in the rectangular window. How should we achieve this?
We know that the straight line segment can be expressed by a parametric equation, assuming that the two endpoints of the straight line segment are (x1,y1), (x2,y2). The parameter equation of the straight line segment can be written as (x-x1) / (x2-x1) =(y-y1)/(y2-y1)=t. at this time, the range of t is [0,1]
The first step is to judge whether a straight line segment will intersect the rectangular window. For a straight line segment, its slope k is known. Set a straight line L: y=k*x+b, let l pass through the four vertices of the window, and get four intercepts. Record the maximum slope bit bmax and the minimum slope is bmin. For a straight line segment in the canvas, first judge whether its slope is between [bmin,bmax]. If not, directly remove the straight line.
If so, consider an idea. With the window as the center, the canvas is divided into 9 areas. The area inside the window is marked as 0 and the area outside the window is marked as 1. Mark the end point of the straight line segment. If the end point is in that area, it will be marked with the mark of the corresponding area.
Suppose the endpoint of the line segment is marked P,Q. If P|Q=0, it means that the straight line segment is in the window and is directly retained. Otherwise, if P & Q = 1, it indicates that there are two intersections with the window and one intersection with the straight line in other cases. The four edges of the rectangular window can also be expressed by parametric equation. Let the straight line segment intersect the four edges in turn, and find the solution, that is, the intersection. Let the parameter of the straight line segment be t and the parameter of the window straight line be u. only when t and u satisfy t,u ∈ [0,1] at the same time is the intersection
The following is the program implementation code

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Code clipping algorithm</title>
	</head>
	<script src="../Assignment 1/dat.gui.js"></script>
	<script language="JavaScript">
		//Properties of the window
		var xl, xr, yb, yt;
		var canvas, context;
		//Stores the two endpoints of a line and their corresponding flag bits
		var line = new Array();

		function init() {
			canvas = document.getElementById("output");
			context = canvas.getContext("2d");
			canvas.width = window.innerWidth;
			canvas.height = window.innerHeight;
			var controls = new function() {
				this.draw=function(){
					context.clearRect(0,0,window.innerWidth,window.innerHeight);
					drawWindow();
					drawLine();
				}
				this.cut = function() {
					//Clip line segment
					cutLine();
					context.clearRect(0,0,window.innerWidth,window.innerHeight);
					//Redescribe
					drawWindow();
					afterShow();
				}
				
			};
			var gui=new dat.GUI();
			gui.add(controls,'draw');
			gui.add(controls,'cut');
			drawWindow();
			drawLine();
		}
		//Draw window
		function drawWindow() {
			//Set window parameters
			xl = window.innerWidth / 4;
			xr = 3 * window.innerWidth / 4;
			yb = window.innerHeight / 4;
			yt = window.innerHeight / 2;

			context.beginPath();
			context.moveTo(xl, yb);
			context.lineTo(xl, yt);
			context.lineTo(xr, yt);
			context.lineTo(xr, yb);
			context.closePath();
			context.stroke();
		}
		//Draw four line segments corresponding to four cases
		function drawLine() {
			//Completely outside the window
			line[0] = new Array();
			line[0]["xb"] = window.innerWidth / 4;
			line[0]["yb"] = window.innerHeight / 8;
			line[0]["xg"] = window.innerWidth / 8;
			line[0]["yg"] = window.innerHeight / 3;
			line[0]["tagb"] = 0;
			line[0]["tagg"] = 0;
			line[0]["isprint"] = false;
			//An intersection
			line[1] = new Array();
			line[1]["xb"] = window.innerWidth / 2;
			line[1]["yb"] = window.innerHeight / 8;
			line[1]["xg"] = 5 * window.innerWidth / 8;
			line[1]["yg"] = 3 * window.innerHeight / 8;
			line[1]["tagb"] = 0;
			line[1]["tagg"] = 0;
			line[1]["isprint"] = false;
			//Completely within the window
			line[2] = new Array();
			line[2]["xb"] = 3 * window.innerWidth / 8;
			line[2]["yb"] = 5 * window.innerHeight / 16;
			line[2]["xg"] = 5 * window.innerWidth / 8;
			line[2]["yg"] = 7 * window.innerHeight / 16;
			line[2]["tagb"] = 0;
			line[2]["tagg"] = 0;
			line[2]["isprint"] = false;
			//There are two intersections with the window
			line[3] = new Array();
			line[3]["xb"] = window.innerWidth / 8;
			line[3]["yb"] = 3 * window.innerHeight / 8;
			line[3]["xg"] = window.innerWidth / 2;
			line[3]["yg"] = 5 * window.innerHeight / 8;
			line[3]["tagb"] = 0;
			line[3]["tagg"] = 0;
			line[3]["isprint"] = false;
			for (var i = 0; i < 4; i++) {
				context.moveTo(line[i]["xb"], line[i]["yb"]);
				context.lineTo(line[i]["xg"], line[i]["yg"]);
			}
			context.stroke();
			SureTag();
		}
		//Mark both ends of the segment
		function SureTag() {
			for (var i = 0; i < 4; i++) {
				line[i]["tagb"] = caculate(line[i]["xb"], line[i]["yb"]);
				line[i]["tagg"] = caculate(line[i]["xg"], line[i]["yg"]);
			}
		}
		//Here, 1 is not returned uniformly in the window
		function caculate(x, y) {
			if (x < xl) {
				return 1;
			} else if (x <= xr) {
				if (y >= yb && y <= yt)
					return 0;
				else
					return 1;
			} else {
				return 1;
			}
		}
		//Code for clipping lines
		function cutLine() {
			var tline=new Array();
			for (var i = 0; i < 4; i++) {
				//The two endpoints are in the window
				if ((line[i]["tagb"] || line[i]["tagg"]) == 0) {
					line[i]["isprint"] = true;
				}
				else {
					//Both endpoints are outside the window
					//There may be no intersections, there may be two intersections, there may be one intersection
					//No intersection and one intersection are treated as not in the window
					if ((line[i]["tagb"] && line[i]["tagg"]) == 1){
						//Not in window
						if(judge(line[i])==false){
							line[i]["isprint"]=false;
						}
						//In the window, cut out the middle segment
						else{
							tline=getCoor(line[i]);
							line[i]["xb"]=tline["xb"];
							line[i]["yb"]=tline["yb"];
							line[i]["xg"]=tline["xg"];
							line[i]["yg"]=tline["yg"];
							line[i]["isprint"]=true;
						}
					}
					//End point in window, crop
					else if (line[i]["tagg"] == 0) {
						tline=getCoor(line[i]);
						line[i]["xb"]=tline["xb"];
						line[i]["yb"]=tline["yb"];
						line[i]["isprint"]=true;
					} 
					//Start point in window, crop
					else {
						tline=getCoor(line[i]);
						line[i]["xg"]=tline["xb"];
						line[i]["yg"]=tline["yb"];
						line[i]["isprint"]=true;
					}
				}
			}

		}
		//Determine whether there is an intersection with the polygon
		function judge(line){
			var b=new Array();
			var maxb=0;
			var minb=0;
			var lineb=0;
			var k=(line["yg"]-line["yb"])/(line["xg"]-line["xb"]);
			//The point oblique equation is obtained
			//y=k*(x-line["xg"])+line["yg"]
			//y=kx+b,b=y-kx
			b[0]=new Array();
			b[0]=yb-k*xl;
			b[1]=new Array();
			b[1]=yb-k*xr;
			b[2]=new Array();
			b[2]=yt-k*xr;
			b[3]=new Array();
			b[3]=yt-k*xl;
			//Intersect with four vertices to find the range of intercept
			maxb=Math.max(b[0],b[1],b[2],b[3]);
			minb=Math.min(b[0],b[1],b[2],b[3]);
			lineb=line["yg"]-k*line["xg"];
			if(lineb>minb && lineb<maxb)
				return true;
			else
				return false;
		}
		//Obtain the coordinates of the intersection, which can be one intersection or two intersections
		function getCoor(line){
			var tline=new Array();
			tline["tag"]=0;
			//What intersection is the record
			//Get the parameter equation of the line, judge the range of t, and get the intersection with that edge
			//y=(1-t)*yb+t*yg
			//x=(1-t)*xb+t*xg
			//Find the intersection with the four edges respectively
			var t=0;
			
			//y=yb
			t=(yb-line["yb"])/(line["yg"]-line["yb"]);
			if(t>=0 && t<=1){
				tline["xb"]=(1-t)*line["xb"]+t*line["xg"];
				tline["yb"]=yb;
				tline["tag"]=1;
			}
			
			//y=yt
			t=(yt-line["yb"])/(line["yg"]-line["yb"]);
			if(t>=0 && t<=1){
				if(tline["tag"]==0){
					tline["xb"]=(1-t)*line["xb"]+t*line["xg"];
					tline["yb"]=yt;
					tline["tag"]=1;
				}
				else{
					tline["xg"]=(1-t)*line["xb"]+t*line["xg"];
					tline["yg"]=yt;
					tline["tag"]=2;
					//There are at most two intersections
					return tline;
				}
			}
			//x=xl
			t=(xl-line["xb"])/(line["xg"]-line["xb"]);
			if(t>=0&&t<=1){
				if(tline["tag"]==0){
					tline["xb"]=xl;
					tline["yb"]=(1-t)*line["yb"]+t*line["yg"];
					tline["tag"]=1;
				}
				else{
					tline["xg"]=xl;
					tline["yg"]=(1-t)*line["yb"]+t*line["yg"];
					tline["tag"]=2;
					//There are at most two intersections
					return tline;
				}
			}
			//x=xr
			t=(xr-line["xb"])/(line["xg"]-line["xb"]);
			if(t>=0&&t<=1){
				if(tline["tag"]==0){
					tline["xb"]=xr;
					tline["yb"]=(1-t)*line["yb"]+t*line["yg"];
					tline["tag"]=1;
				}
				else{
					tline["xg"]=xr;
					tline["yg"]=(1-t)*line["yb"]+t*line["yg"];
					tline["tag"]=2;
					//There are at most two intersections
					return tline;
				}
			}
			return tline;
		}
		function afterShow(){
			for(var i=0;i<4;i++){
					if(line[i]["isprint"]==true){
					context.moveTo(line[i]["xb"],line[i]["yb"]);
					context.lineTo(line[i]["xg"],line[i]["yg"]);
				}
			}
			context.stroke();	
		}
		window.onload = init;
	</script>
	<body>
		<canvas id="output"></canvas>
	</body>
</html>

Initial state

After clicking cut in the upper right corner

It can be seen that the code successfully cuts the straight line segment and retains the straight line segment in the window.

Posted by Jeyush on Fri, 05 Nov 2021 23:45:29 -0700