//============================================================================= // NGeometryUtilities::ClipLineToRectangle : Clip a line to a rectangle. //----------------------------------------------------------------------------- // Note : Clips using Cohen-Sutherland. //----------------------------------------------------------------------------- template<class T> NGeometryComparison NGeometryUtilities::ClipLineToRectangle( const NRectangleT<T> &theRect, const std::vector< NPointT<T> > &theInput, std::vector< NPointT<T> > &theOutput) { T dx, dy, minX, maxX, minY, maxY; NBitfield code0, code1, codeOut; NPointT<T> p0, p1, pointOut; NGeometryComparison theResult; // Get the state we need p0 = theInput[0]; p1 = theInput[1]; code0 = GetClipCode(theRect, p0); code1 = GetClipCode(theRect, p1); // Both points are outside if ((code0 & code1) != 0) { theOutput.clear(); return(kNGeometryOutside); } // Both points are inside else if ((code0 | code1) == 0) { theOutput = theInput; return(kNGeometryInside); } // Intersection // // We pick an exterior point, then clip the segment to an edge. if (code0 != 0) { codeOut = code0; pointOut = p0; } else { codeOut = code1; pointOut = p1; } dx = p1.x - p0.x; dy = p1.y - p0.y; minX = theRect.GetMinX(); maxX = theRect.GetMaxX(); minY = theRect.GetMinY(); maxY = theRect.GetMaxY(); // Split line at top of rectangle if (codeOut & kNGeometryClipTop) { pointOut.x = p0.x + (dx * ((maxY - p0.y) / dy)); pointOut.y = maxY; } // Split line at bottom of rectangle else if (codeOut & kNGeometryClipBottom) { pointOut.x = p0.x + (dx * ((minY - p0.y) / dy)); pointOut.y = minY; } // Split line at right edge of rectangle else if (codeOut & kNGeometryClipRight) { pointOut.x = maxX; pointOut.y = p0.y + (dy * ((maxX - p0.x) / dx)); } // Split line at left edge of rectangle else if (codeOut & kNGeometryClipLeft) { pointOut.x = minX; pointOut.y = p0.y + (dy * ((minX - p0.x) / dx)); } else NN_LOG("Invalid codeOut: %d", codeOut); // Clip the new segment if (codeOut == code0) theResult = ClipLineToRectangle(theRect, vector(pointOut, p1), theOutput); else theResult = ClipLineToRectangle(theRect, vector(p0, pointOut), theOutput); // Update the result // // Since we know we had an intersection with one of the rectangle edges, // a result of inside is actually an intersection. // // A result of outside indicates the line intersected an edge but didn't // encroach on the rectangle itself so that result remains. if (theResult == kNGeometryInside) theResult = kNGeometryIntersects; return(theResult); }
static int ClipLine(const AbsRectangle &clipping, core::position2d<s32> &p0, core::position2d<s32> &p1, const core::position2d<s32>& p0_in, const core::position2d<s32>& p1_in) { u32 code0; u32 code1; u32 code; p0 = p0_in; p1 = p1_in; code0 = GetClipCode( clipping, p0 ); code1 = GetClipCode( clipping, p1 ); // trivial accepted while ( code0 | code1 ) { s32 x=0; s32 y=0; // trivial reject if ( code0 & code1 ) return 0; if ( code0 ) { // clip first point code = code0; } else { // clip last point code = code1; } if ( (code & CLIPCODE_BOTTOM) == CLIPCODE_BOTTOM ) { // clip bottom viewport y = clipping.y1; x = p0.X + ( p1.X - p0.X ) * ( y - p0.Y ) / ( p1.Y - p0.Y ); } else if ( (code & CLIPCODE_TOP) == CLIPCODE_TOP ) { // clip to viewport y = clipping.y0; x = p0.X + ( p1.X - p0.X ) * ( y - p0.Y ) / ( p1.Y - p0.Y ); } else if ( (code & CLIPCODE_RIGHT) == CLIPCODE_RIGHT ) { // clip right viewport x = clipping.x1; y = p0.Y + ( p1.Y - p0.Y ) * ( x - p0.X ) / ( p1.X - p0.X ); } else if ( (code & CLIPCODE_LEFT) == CLIPCODE_LEFT ) { // clip left viewport x = clipping.x0; y = p0.Y + ( p1.Y - p0.Y ) * ( x - p0.X ) / ( p1.X - p0.X ); } if ( code == code0 ) { // modify first point p0.X = x; p0.Y = y; code0 = GetClipCode( clipping, p0 ); } else { // modify second point p1.X = x; p1.Y = y; code1 = GetClipCode( clipping, p1 ); } } return 1; }