Exemplo n.º 1
0
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();
    }
}