[net.sources] 2d, 3d clipping

grunwald@uiucdcsb.UUCP (02/27/85)

    The following file contains an implementation of the new line-clipping
algorithm presented in the Jan '84 Trans. on Graphics using the parametric
equation for the line to do the actual clipping. The routines return a boolean
value as to whether the line was rejected from the view-volume, and if it
was not rejected, it clips the points to the view column. Both the 2d and the
3d cases are given. A simple "fast check" for clipping to an integer-sized
view volume is also given. Using the later to determine if 2d cliping is
really needed seems to make for a considerable savings. The structure "Point"
is obvious, as is the "clip_struct".
	I copy the points into local variables on the assumption that this is
faster than dereferencing the structure variables each time. I'm not sure that
this is true. I've tested this code on a Sun workstation and it works pretty
well. You'd be well advised to use an in-line version of the "check if we
need to clip" routine or it'll crawl.
-------------------------------------------------------------------------------
#include "0.h"

/*
 *	Line clipping algorithms as taken from ACM TOG Vol 3 No 1
 *
 *	The bounding area for the X-Y plane is defined by the points
 *	(clip_xmin, clip_ymin) and (clip_xmax, clip_ymax).
 *
 *	For the three-dimensional case, the hither plane corresponds to
 *	clip_zmin and the yon plan corresponds to clip_zmax
 */

#define	FALSE 0

static int
clipt(p, q, t0, t1)
float	p, q;
float	*t0, *t1;
{
    float r;

    if (p < 0.0) {
	r = q / p;
	if (r > *t1)
	    return( FALSE );
	else
	    if (r > *t0) *t0 = r;
    }
    else if ( p > 0.0 ) {
	r = q / p;
	if (r < *t0)
	    return( FALSE );
	else
	    if (r < *t1) *t1 = r;
    }
    else
	if (q < 0.0) return( FALSE );

    return ( ! FALSE );
}

fastcheck2d(x0, y0, x1, y2, minx, maxx, miny, maxy)
int x0, y0;
int x1, y1;
int minx, maxx;
int miny, maxy;
{
/*
 *	Check for simple acceptance. Most line segments will fall into
 *	this catagory we should hope.
 */

    return(	x0 <= maxx && x0 >= minx &&
		x1 <= maxx && x1 >= minx &&
		y0 <= maxy && y0 >= miny &&
		y1 <= maxy && y1 >= miny) ;
}

clip2d( p0, p1, clp )
struct Point *p0, *p1;
struct clip_struct *clp;
{
    float t0, t1;
    float deltax, deltay;
    float lx0, ly0;
    float lx1, ly1;

    int isok = 0;

    lx0 = p0 -> x;	ly0 = p0 -> y;
    lx1 = p1 -> x;	ly1 = p1 -> y;

    t0 = 0.0;
    t1 = 1.0;
    deltax = lx1 - lx0;

    if ( clipt(-deltax, lx0 - (clp -> clip_xmin), &t0, &t1) &&
	 clipt(deltax, (clp -> clip_xmax) - lx0, &t0, &t1) ) {

	deltay = ly1 - ly0;

	if ( clipt( -deltay, ly0 - (clp -> clip_ymin), &t0, &t1) &&
	     clipt(deltay, (clp -> clip_ymax) - ly0, &t0, &t1) ) {

	    isok = 1;

	    if (t1 < 1.0) {
		lx1 = lx0 + t1 * deltax;
		ly1 = ly0 + t1 * deltay;
	    }

	    if (t0 > 0.0) {
		lx0 = lx0 + t0 * deltax;
		ly0 = ly0 + t0 * deltay;
	    }
	}
    }
	
    p0 -> x = lx0;	p0 -> y = ly0;
    p1 -> x = lx1;	p1 -> y = ly1;

    return( isok );
}

clip3d( p0, p1, clp )
struct Point *p0, *p1;
struct clip_struct *clp;
{
    float t0, t1;
    float deltax, deltay, deltaz;
    float lx0, ly0, lz0;
    float lx1, ly1, lz1;

    int isok = 0;

    lx0 = p0 -> x;	ly0 = p0 -> y;		lz0 = p0 -> z;
    lx1 = p1 -> x;	ly1 = p1 -> y;		lz1 = p1 -> z;

    t0 = 0.0;
    t1 = 1.0;

    deltax = lx1 - lx0;
    deltaz = lz1 - lz0;

    if ( clipt( -deltax-deltaz, lx0 + lz0, &t0, &t1) &&
	 clipt(deltax - deltaz, lz0 - lx0, &t0, &t1) ) {

	deltay = ly1 - ly0;

	if ( clipt( -deltay-deltaz, ly0 + lz0, &t0, &t1) &&
	     clipt(deltay-deltaz, lz0 - ly0, &t0, &t1) ) {

	    if ( clipt( -deltaz, lz0 - clp -> clip_zmin, &t0, &t1) &&
		clipt( deltaz, clp -> clip_zmax - lz0, &t0, &t1) ) {

		isok = 1;

		if (t1 < 1.0) {
		    lx1 = lx0 + t1 * deltax;
		    ly1 = ly0 + t1 * deltay;
		    lz1 = lz0 + t1 * deltaz;
		}

		if (t0 > 0.0) {
		    lx0 = lx0 + t0 * deltax;
		    ly0 = ly0 + t0 * deltay;
		    lz0 = lz0 + t0 * deltaz;
		}
	    }
	}
    }
	
    p0 -> x = lx0;	p0 -> y = ly0;		p0 -> z = lz0;
    p1 -> x = lx1;	p1 -> y = ly1;		p1 -> z = lz1;

    return( isok );
}