// LiBarClipLib.h // NKU CSC 480 - Kirby // ------------------------------------------------------------------- // C functions implementing a 2D Liang-Barsky parametric line clipper. // Generalization to 3D is obvious and easy. // ------------------------------------------------------------------- struct Rect // A 2D axis-aligned rectangle. { Rect( float xmin, float xmax, float ymin, float ymax ) : xmin(xmin), xmax(xmax), ymin(ymin), ymax(ymax ) {} float xmin, xmax, ymin, ymax ; } ; inline bool edgeTest( float delta, float gap, float& tLo, float& tHi ) // Returns false if line is definitively clipped out of entire rectangle. // Otherwise, update parameter interval [tLo, tHi]. // Edge intersection is characterized by Liang-Barsky delta and gap values. { float t ; if ( delta == 0 ) { // line is parallel to edge return gap > 0 ; } else if ( delta < 0 ) { // line runs inward t= gap / delta ; if ( t > tHi ) return false ; // stops before entering if ( t > tLo ) tLo= t ; // crosses inward; advance tLo to t return true ; } else // d > 0 { // line runs outward t= gap / delta ; if ( t < tLo ) return false ; // starts after exiting if ( t < tHi ) tHi= t ; // crosses outward; retract tHi to t return true ; } } inline bool clip( const Rect& rect, float& xA, float& yA, float& xB, float& yB ) // Clip line (xA,yA)-(xB,yB) to given rectangle. // Liang-Barsky algorithm. { float dx= xB - xA ; float dy= yB - yA ; // Initial parameter values. float tLo=0, tHi= 1 ; // Update [tLo,tHi] for each edge, bailing out whenever invisibility is certain. // Short-circuiting is important here. bool visible= edgeTest( -dx, xA - rect.xmin, tLo, tHi ) // left && edgeTest( dx, rect.xmax - xA, tLo, tHi ) // right && edgeTest( -dy, yA - rect.ymin, tLo, tHi ) // bottom && edgeTest( dy, rect.ymax - yA, tLo, tHi ) ; // top if ( ! visible ) return false ; // Retract the end points. if ( tHi < 1 ) { xB= xA + tHi * dx ; yB= yA + tHi * dy ; } // Advance the start points. if ( tLo > 0 ) { xA += tLo * dx ; yA += tLo * dy ; } return true ; }