0 Write an OpenGL Program to implement the Cohen-Sutherland line-clipping algorithm. Make provision to specify the input line, window for clipping and view port for displaying the clipped image. The plane in which the window lies is divided into nine regions each with a different outcode. Outcodes of a point are integers(we use only last four bits) with appropriate bits set/reset to indicate the region in which that point lies. The advantage of using region codes is that it makes it extremely simple to accept/reject a line which is completely inside/outside a window. Outcode of two points inside the window is 0000 and 0000 and bitwise OR of these codes yields a zero hence this line can be accepted. Outcode of two points lying completely on one side of the window either to left or right or top or bottom implies that one bit of both the outcodes is set(1). So a bitwise AND of the outcodes yields a non zero value which indicates that the line is completely on one side and hence rejected. We need to find the multiple intersection points of a line with the four edges, if it intersects an edge and some part is inside the window. */ #include<stdio.h> #include<GL/glut.h> #define outcode int double xmin=50,ymin=50,xmax=100,ymax=100;// Windows boundaries double xvmin=200,yvmin =200, xvmax=300,yvmax=300; // Viewport boundaries const int RIGHT= 8; // bit codes for the right const int LEFT =2; //bit codes for the left const int TOP=4; // bit codes for the top const int BOTTOM=1; //bit codes for the bottom outcode ComputeOutCode(double x,double y); // used to compute bit codes of a point // Cohen -Sutherland clipping algorithm clips a line from // p0=(x0,y0) to p1 =(x1,y1) against a rectangle with. // diagonal from (xmin,ymin)to (xmax,ymax) void CohenSutherlandLineClipAnddraw(double x0,double y0,double x1,double y1) { // OutCodes for P0 ,P1 and Whatever point(among P0 & P1) lies outside the // clip rectangle outcode outcode0,outcode1,outcodeOut; int accept =0,done =0;// These are two bits to indicate trivial accept and/or // done with clipping //compute outcodes outcode0= ComputeOutCode(x0,y0); outcode1= ComputeOutCode(x1,y1); do { if(!(outcode0|outcode1)) // logical or is 0 trivially accept and exit { accept=1; done=1; } else if(outcode0 & outcode1) // logical and is 0 trivially reject and exit done=1; else { //failed both tests , so calculate the line segment clip; // from an outside point to an intersection with clip edge double x,y; // at least one endpoint is outside the clip rectangle ; pick it. outcodeOut= outcode0?outcode0:outcode1; //now find the intersection point ; slope m= (y1-y0)/(x1-x0) // use formula /// y=y0+slope*(x-x0), //either x is xmin or xmax /// x=x0+(1/slope)*(y-y0) // y is ymin or ymax if(outcodeOut & TOP) //point is above the clip rectangle { x= x0+(x1-x0)*(ymax-y0)/(y1-y0); y=ymax; } else if(outcodeOut & BOTTOM) //point is below the clip rectangle { x= x0+(x1-x0)*(ymin-y0)/(y1-y0); y=ymin; } else if(outcodeOut & RIGHT) //point is to the right of clip rectangle { y= y0+(y1-y0)*(xmax-x0)/(x1-x0); x=xmax; } else //point is to the left of the clip rectangle { y= y0+(y1-y0)*(xmin-x0)/(x1-x0); x=xmin; } // now we move outside point to intersection point to clip // and get ready for next pass. if(outcodeOut == outcode0) // If the outside point was p0 update x0,y0 to x,y { x0=x; // so x,y become the new x0,y0 y0=y; outcode0 = ComputeOutCode(x0,y0); //compute outcode of new endpoint } else // If the outside point was p1 update x1,y1 to x,y { // so x,y becomes the new x1,y1 x1=x; y1=y; outcode1 = ComputeOutCode(x1,y1); // compute outcode of new endpoint } } }while(!done); if(accept) //If line was trivial reject no need to draw viewport { // window to viewport mapping double sx=(xvmax-xvmin)/(xmax-xmin);// scale parameter in x direction double sy=(yvmax-yvmin)/(ymax-ymin);// scale parameter in y direction double vx0 = xvmin+(x0-xmin)*sx; double vy0 = yvmin+(y0-ymin)*sy; double vx1 = xvmin+(x1-xmin)*sx; double vy1 = yvmin+(y1-ymin)*sy; //draw a red color viewport glColor3f(1.0,0.0,0.0); glBegin(GL_LINE_LOOP); glVertex2f(xvmin,yvmin); glVertex2f(xvmax,yvmin); glVertex2f(xvmax,yvmax); glVertex2f(xvmin,yvmax); glEnd(); glColor3f(0.0,0.0,1.0); glBegin(GL_LINES); glVertex2d(vx0,vy0); glVertex2d(vx1,vy1); glEnd(); } } // compute the bit code for a point (x,y) using the clip rectangle // bounded diagonally by (xmin,ymin) and (xmax,ymax) outcode ComputeOutCode(double x,double y) { outcode code =0; if(y>ymax) //above the clip window code |=TOP; if(y<ymin) //below the clip window code |=BOTTOM; if(x>xmax) //to the right of the clip window code |=RIGHT; if(x<xmin) //to the left of the clip window code |=TOP; return code; } void display() { double x0=120,y0=10,x1=40,y1=130; glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.0,0.0); // draw red color lines glBegin(GL_LINES); glVertex2d(x0,y0); glVertex2d(x1,y1); glVertex2d(60,20); glVertex2d(80,120); glEnd(); glColor3f(0.0,0.0,1.0); // draw a blue colored window glBegin(GL_LINE_LOOP); glVertex2f(xmin,ymin); glVertex2f(xmax,ymin); glVertex2f(xmax,ymax); glVertex2f(xmin,ymax); glEnd(); CohenSutherlandLineClipAnddraw(x0,y0,x1,y1); CohenSutherlandLineClipAnddraw(60,20,80,120); glFlush(); } void myinit() { glClearColor(1.0,1.0,1.0,1.0); glColor3f(1.0,0.0,0.0); glPointSize(1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,499.0,0.0,499.0); } int main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("cohen Sutherland line clipping algorithm"); glutDisplayFunc(display); myinit(); glutMainLoop(); return 0; } Scan-line area Scan-line area filling uses the property of coherence to color the polygon. Scanline coherence means if a point lies inside a polygon then other points lying on the same scanline near to it are also likely to be inside the polygon. There are various ways to check if a point is inside the polygon or not. If somehow all pixels lying inside are found out then it is just a matter of changing their pixel value to color the polygon. In this program it uses two arrays le and re denoting left edge and right edge. They span the entire window height(500-array size) and store the position(x value) of the intersection point of the scan line with one of the edges of polygon(either left or right). Initial values in le array is 500. That of re array is 0. We scan convert individual edges of the polygon and each point on the edge, its x value goes to the correct le or re array. Finally once le and re arrays are populated we draw a line from the left edge to the right edge in a loop and iterate over the entire window region(all 500 scanlines). #include<stdio.h> #include<GL/glut.h> GLfloat x1,y1,x2,y2,x3,y3,x4,y4; void edgedetect(GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2,int *le,int *re) { float mx,x,temp; int i; if((y2-y1)<0) // if second point is below first point interchange them { temp=x1;x1=x2;x2=temp; temp=y1;y1=y2;y2=temp; } if((y2-y1)!=0) // if denominator is zero we can't find slope mx=(x2-x1)/(y2-y1); else mx=x2-x1; // y2-y1=0 implies line is horizontal x=x1; for(i=y1;i<y2;i++) // starting from x1,y1 add slope mx to x { // and round it to find the next point on the // line. For that particular scan line i if(x<le[i]) // insert the x value into either le or re. le[i]=x; // Initially both le and re will contain same // value... if(x>re[i]) // in the next time for the other edge re[i]=x; // either le or re will change x+=mx; // NOTE: le and re are integer arrays and x } // is float so automatic type conversion. } void drawpixel(int x,int y) { glColor3f(0.0,1.0,1.0); glBegin(GL_POINTS); glVertex2i(x,y); glEnd(); } void scanfill(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4) { int le[500],re[500]; int i,y; for(i=0;i<500;i++) // initialize le and re array values { le[i]=500; re[i]=0; } edgedetect(x1,y1,x2,y2,le,re); // call edge detect four times edgedetect(x2,y2,x3,y3,le,re); // once for each edge. edgedetect(x3,y3,x4,y4,le,re); edgedetect(x4,y4,x1,y1,le,re); for(y=0;y<500;y++) // for every scan line with value y { if(le[y]<=re[y]) // refer to le and re arrays to see if a part for(i=le[y]+1;i<re[y];i++) // of the scanline is inside polygon drawpixel(i,y); // if so draw a horizontal line from } // left edge to right edge } void display() { glClear(GL_COLOR_BUFFER_BIT); x1=200,y1=200,x2=100,y2=300,x3=200,y3=400,x4=300,y4=300; glBegin(GL_LINE_LOOP); // draw the boundary of the polygon glVertex2f(x1,y1); // to be filled. glVertex2f(x2,y2); glVertex2f(x3,y3); glVertex2f(x4,y4); glEnd(); scanfill(x1,y1,x2,y2,x3,y3,x4,y4); // call scanfill to fill the polygon glFlush(); // Usually students fail the lab because they forget glFlush. } void myinit() { glClearColor(1.0,1.0,1.0,1.0); glColor3f(0.0,0.0,1.0); glPointSize(1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,499.0,0.0,499.0); } int main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500,500);// 500 height is hardcoded glutInitWindowPosition(0,0); glutCreateWindow("scanfill"); glutDisplayFunc(display); myinit(); glutMainLoop(); return 0; } LAING BARSKY This is a parametric line clipping algorithm. The parameter t is a fraction between 0 and 1. So your lessons in ratios in school are useful in this program. The thing is if we know the parameter t on a line from (x1,y1) to (x2,y2) we can find any point(x,y) on the line by: x=x1+t*dx; y=y1+t*dy; where dx and dy are x2-x1 and y2-y1 respectively. So starting from (x1,y1) t gives an idea of how much far have we gone towards (x2,y2). For clipping we find t value of intersection points. There are four intersection points of a line with four edges of the window. If at an intersection point if line is going into the window it means it is a potentially entering point. If intersection point is such that line is leaving the window then it is potentially leaving. We consider lines going from left to right and bottom to top. Argument holds if line is in any other direction. In this figure Line number 1 looks proper and its part is inside the window. It starts with line entering bottom edge then entering left edge then leaving top edge and then leaving right edge. Something wrong with Line Number 2. It enters bottom edge then leaves top edge and then enters left edge and then leaves right edge(not shown). So since entering intersection point has crossed over after the leaving intersection point. Hence the line is rejected. Lines no. 3 are horizontal and dy=0 so they go to third condition in cliptest function and are rejected. Ditto with lines no 4. where dx=0; */ #include<stdio.h> #include<GL/glut.h> double xmin=50, ymin=50, xmax=100,ymax=100; //window boundaries double xvmin=200,yvmin=200,xvmax=300, yvmax=300; //viewport boundaries int x1,y1,x2,y2; int cliptest(double p,double q,double *t1,double *t2) { // p is denominator in division and q is numerator // t1 is t entering and t2 is t leaving double t=q/p; if(p<0.0) //potentially entry point ,update te { if(t>*t1) *t1=t; if(t>*t2) return(0); //line portion is outside as in line no 2 where t(entering) // has become more than t(leaving) } else if(p>0.0) //potentially leaving point ,update tl { if(t<*t2) *t2=t; if(t<*t1) return(0); //line portion is outside } else if(p==0.0) { if(q<0.0) return(0);//line parallel to edge but outside } return(1); } void liangbaraskylineclipanddraw(double x0,double y0,double x1,double y1) { double dx= x1-x0,dy=y1-y0, te=0.0,tl=1.0; if(cliptest(-dx,x0-xmin,&te,&tl))// inside test wrt left edge // t for the left edge is t=(xmin-x0) /dx .... order of numerator is reversed and you get -dx if(cliptest(dx,xmax-x0,&te,&tl))// inside test wrt right edge // t for the right edge is t=(xmax-x0)/dx.... first parameter becomes q and second p then t=q/p if(cliptest(-dy,y0-ymin,&te,&tl))// inside test wrt bottom edge // same story numerator by demoninator to find t if(cliptest(dy,ymax-y0,&te,&tl))// inside test wrt top edge // in one way cohen sutherland and liang barasky are similar { if(tl<1.0) { x1=x0+tl*dx; y1=y0+tl*dy; } if(te>0.0) { x0=x0+te*dx; y0=y0+te*dy; } } //window to viewport mappings double sx= (xvmax-xvmin)/(xmax-xmin);// scale parameters double sy= (yvmax-yvmin)/(ymax-ymin); double vx0= xvmin+(x0-xmin)*sx; double vy0= yvmin+(y0-ymin)*sy; double vx1= xvmin+(x1-xmin)*sx; double vy1= yvmin+(y1-ymin)*sy; // draw a red colored viewport glColor3f(1.0,0.0,0.0); glBegin(GL_LINE_LOOP); glVertex2f(xvmin,yvmin); glVertex2f(xvmax,yvmin); glVertex2f(xvmax,yvmax); glVertex2f(xvmin,yvmax); glEnd(); glColor3f(0.0,0.0,1.0); //draw blue colored clip line glBegin(GL_LINES); glVertex2d(vx0,vy0); glVertex2f(vx1,vy1); glEnd(); } void display() { double x0=60,y0=20,x1=80,y1=120; glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.0,0.0); //draw a line with red color glBegin(GL_LINES); glVertex2d(x0,y0); glVertex2d(x1,y1); glEnd(); glColor3f(0.0,0.0,1.0); //draw a blue color window glBegin(GL_LINE_LOOP); glVertex2f(xmin,ymin); glVertex2f(xmax,ymin); glVertex2f(xmax,ymax); glVertex2f(xmin,ymax); glEnd(); liangbaraskylineclipanddraw(x0,y0,x1,y1); glFlush(); } void myinit() { glClearColor(1.0,1.0,1.0,1.0); glColor3f(1.0,0.0,0.0); glPointSize(1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,499.0,0.0,499.0); } int main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("liang barsky line clipping algorithm"); glutDisplayFunc(display); myinit(); glutMainLoop(); return 0; } In computer graphics, 'line clipping' is the process of removing lines or portions of lines outside of an area of interest. Typically, any line or part thereof which is outside of the viewing area is removed. The Liang-Barsky algorithm uses the parametric equation of a line and inequalities describing the range of the clipping window to determine the intersections between the line and the clipping window. With these intersections it knows which portion of the line should be drawn. Algorithm: 1. End-points pairs are check for trivial acceptance or trivial rejected using the outcode. 2. If not trivial-accepance or trivial-rejected, divided into two segments at a clip edge. 3. Iteratively clipped by testing trivial-acceptance or trivial-rejected, and divided into two segments until completely inside or trivial-rejected. 4. To perform trivial accept and reject tests, we extend the edges of the clip rectangle to divide the plane of the clip rectangle into nine regions. Each region is assigned a 4-bit code deteermined by where the region lies with respect to the outside halfplanes of the clip-rectangle edges. Each bit in the outcode is set to either 1 (true) or 0 (false); the 4 bits in the code correspond to the following conditions: o Bit 1 : outside halfplane of top edge, above top edge Y > Ymax o Bit 2 : outside halfplane of bottom edge, below bottom edge Y < Ymin o Bit 3 : outside halfplane of right edge, to the right of right edge X > Xmax o Bit 4 : outside halfplane of left edge, to the left of left edge X < Xmin Theory In computer graphics, 'line clipping' is the process of removing lines or portions of lines outside of an area of interest. Typically, any line or part thereof which is outside of the viewing area is removed. The Cohen�Sutherland algorithm is a computer graphics algorithm used for line clipping. The algorithm divides a two-dimensional space into 9 regions (or a three-dimensional space into 27 regions), and then efficiently determines the lines and portions of lines that are visible in the center region of interest (the viewport). The algorithm quickly detects and dispenses with two common and trivial cases. To clip a line, we need to consider only its endpoints. If both endpoints of a line lie inside the window, the entire line lies inside the window. It is trivially accepted and needs no clipping. On the other hand, if both endpoints of a line lie entirely to one side of the window, the line must lie entirely outside of the window. It is trivially rejected and needs to be neither clipped nor displayed.