Liang – Barsky Polygon Clipping

Steve on Apr 7th 2009

If you’d like to see this code tidied up slightly and working in an example, see my post Liang-Barsky Polygon Clipping Example.

	//
	// This routine uses the Liang-Barsky algorithm for polygon clipping as
	// desribed in Foley & van Dam.  It's more efficient than the above
	// Sutherland-Hodgman, but produces redundent turning vertices at the
	// corners of the clip region.  This makes rendering as a series of
	// triangles very awkward.
	//

	public static final int INFINITY = 2147483647;

	public int LiangBarskyPolygonClip(
		int n,
		int [] x, int [] y,		// vertices of input polygon
		int [] u, int [] v) {	// vertices of output polygon

		int outCount = 0;

		int xIn, xOut, yIn, yOut;					// Coordinates of entry and exit points
		int tOut1, tIn2, tOut2;						// Parameter values of same
		int tInX, tOutX, tInY, tOutY;				// Parameter values for intersection
		int deltaX, deltaY;							// Direction of edge
		int i;

		// Assume polygon is closed
		x[n] = x[0];
		y[n] = y[0];

		for(i = 0; i < n; i++) {	// for each edge 

			deltaX = x[i+1] - x[i];	// determine direction of edge
			deltaY = y[i+1] - y[i];	

			// use this to determine which bounding lines for the clip region the
			// containing line hits first
			if((deltaX > 0) || (deltaX == 0 && x[i] > clip_x_max)) {
				xIn = clip_x_min; xOut = clip_x_max;
			} else {
				xIn = clip_x_max; xOut = clip_x_min;
			}
			if((deltaY > 0) || (deltaY == 0 && y[i] > clip_y_max)) {
				yIn = clip_y_min; yOut = clip_y_max;
			} else {
				yIn = clip_y_max; yOut = clip_y_min;
			}

			// find the t values for the x and y exit points
			if(deltaX != 0) {
				tOutX = ((xOut - x[i])<<8) / deltaX;
			} else if(x[i] <= clip_x_max && clip_x_min <= x[i])
				tOutX = INFINITY;
			else
				tOutX = -INFINITY;

			if(deltaY != 0) {
				tOutY = ((yOut - y[i])<<8) / deltaY;
			} else if(y[i] <= clip_y_max && clip_y_min <= y[i])
				tOutY = INFINITY;
			else
				tOutY = -INFINITY;

			// Order the two exit points
			if(tOutX < tOutY) {
				tOut1 = tOutX; tOut2 = tOutY;
			} else {
				tOut1 = tOutY; tOut2 = tOutX;
			}

			if(tOut2 > 0) {

				if(deltaX != 0)
					tInX = ((xIn - x[i])<<8) / deltaX;
				else
					tInX = -INFINITY;

				if(deltaY != 0)
					tInY = ((yIn - y[i])<<8) / deltaY;
				else
					tInY = -INFINITY;

				if(tInX < tInY)
					tIn2 = tInY;
				else
					tIn2 = tInX;

				if(tOut1 < tIn2) {	// no visible segment
					if(0 < tOut1 && tOut1 <= (1<<8)) {
						// line crosses over intermediate corner region
						if(tInX < tInY) {
							u[outCount] = xOut;
							v[outCount] = yIn;
						} else {
							u[outCount] = xIn;
							v[outCount] = yOut;
						}
						outCount++;
					}

				} else {

					// line crosses though window
					if(0 < tOut1 && tIn2 <= (1<<8)) {
						if(0 <= tIn2) {	// visible segment
							if(tInX > tInY) {
								u[outCount] = xIn;
								v[outCount] = y[i] + ((tInX * deltaY)>>8);
							} else {
								u[outCount] = x[i] + ((tInY * deltaX)>>8);
								v[outCount] = yIn;
							}
							outCount++;
						}

						if((1<<8) >= tOut1) {
							if(tOutX < tOutY) {
								u[outCount] = xOut;
								v[outCount] = y[i] + ((tOutX * deltaY)>>8);
							} else {
								u[outCount] = x[i] + ((tOutY * deltaX)>>8);
								v[outCount] = yOut;
							}
							outCount++;
						} else {
							u[outCount] = x[i+1];
							v[outCount] = y[i+1];
							outCount++;
						}
					}

				}

				if(0 < tOut2 && tOut2 <= (1<<8)) {
					u[outCount] = xOut;
					v[outCount] = yOut;
					outCount++;
				}

			}
		} 

		return outCount;
	}
Share this post:
  • Digg
  • Reddit
  • del.icio.us
  • Technorati
  • Google Bookmarks
  • Facebook
  • StumbleUpon
  • Twitter

No responses yet

Trackback URI | Comments RSS

Leave a Reply

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word