File - I save myself

advertisement
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.
Download