ClippingTestResult CohenSutherlandLineClipper::ClipLine (LineSegment2F & line, Rectangle2F const& clipRect) const { // Until we have a trivial accept or reject, // 1. Compute outcodes for start and end points // 2. If start | end is 0, trivial accept // Else if start & end is not 0, trivial reject // Else, // a) Find the outcode of the "out" point (the one whose outcode is non-zero), // b) Update this to the intersection of the line and the appropriate clip rectangle border edge...take advantage of outcode when computing auto result = ClippingTestResult::NON_TRIVIAL; while (result == ClippingTestResult::NON_TRIVIAL) { auto outcode_start = ComputeOutcode(line.start, clipRect); auto outcode_end = ComputeOutcode(line.end , clipRect); if ((outcode_start | outcode_end) == 0) // both points are within clip rectangle { result = ClippingTestResult::TRIVIAL_ACCEPT; } else if ((outcode_start & outcode_end) != 0) // both points are outside of clip rectangle { result = ClippingTestResult::TRIVIAL_REJECT; } else // at least one point is within the clip rectangle { // Given two points (x0, y0), (x1, y1): // Slope `m` = (y1 - y0) / (x1 - x0) // Equation for `x` = x0 + (y - y0)/m // Equation for `y` = y0 + (x - x0)*m float x0 = line.start.x, x1 = line.end.x; float y0 = line.start.y, y1 = line.end.y; float m = (y1 - y0) / (x1 - x0); float xmin = clipRect.x, xmax = clipRect.x + clipRect.width; float ymin = clipRect.y - clipRect.height, ymax = clipRect.y; auto IsStartOutside = [=](void){ return outcode_start != 0; }; auto outcode_out = IsStartOutside() ? outcode_start : outcode_end; Point2F & updated = IsStartOutside() ? line.start : line.end; // Update the point that we determined is outside the clip rect if (outcode_out & LEFT) // set x = xmin, solve for y { updated.x = xmin; updated.y = y0 + (updated.x - x0) * m; } else if (outcode_out & RIGHT) // set x = xmax, solve for y { updated.x = xmax; updated.y = y0 + (updated.x - x0) * m; } else if (outcode_out & TOP) // set y = ymax, solve for x { updated.y = ymax; updated.x = x0 + (updated.y - y0) / m; } else if (outcode_out & BOTTOM) // set y = ymin, solve for x { updated.y = ymin; updated.x = x0 + (updated.y - y0) / m; } } } return result; }
// Cohen-Sutherland clipping algo clips a line from // P0=(x0,y) 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) { outcode outcode0,outcode1,outcodeOut; bool accept=false,done=false; // compute outcodes outcode0=ComputeOutcode(x0,y0); outcode1=ComputeOutcode(x1,y1); do { // logical or is 0 Trivially accept & exit if(!(outcode0|outcode1)) { accept=true; done=true; } // logical and is not 0.Trivially reject & exit else if(outcode0 & outcode1) { done=true; } else { // failed both tests,so calculate the line segment to clip // from an outside point to an intersection with clip edge double x,y; //Atleast one endpoint is outside the clip rectangle,pick it. outcodeOut=outcode0?outcode0:outcode1; //Now find the intersection point //use formula y=y0+slope*(x-x0), x=x0+(1/slope)*(y-y0) //point is above the rectangular clip if(outcodeOut & TOP) { x=x0+(x1-x0)*(ymax-y0)/(y1-y0); y=ymax; } // point is below the clip rectangle else if(outcodeOut & BOTTOM) { x=x0+(x1-x0)*(ymin-y0)/(y1-y0); y=ymin; } // point lies right of clipping rectangle else if(outcodeOut & RIGHT) { y=y0+(y1-y0)*(xmax-x0)/(x1-x0); x=xmax; } // point lies leftside of clipping rectangle else { 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) { x0=x; y0=y; outcode0=ComputeOutcode(x0,y0); } else { x1=x; y1=y; outcode1=ComputeOutcode(x1,y1); } } } while(!done); if(accept) { // Window to viewport mappings // scaling parameters double sx=(xvmax-xvmin)/(xmax-xmin); 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 coloured 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(); // draws blue colour viewport glColor3f(0.0,0.0,1.0); glBegin(GL_LINES); glVertex2d(vx0,vy0); glVertex2d(vx1,vy1); glEnd(); } }