[comp.graphics] polygon clipping alg.

hdaffin@oucsace.cs.OHIOU.EDU (Howard Daffin) (05/02/89)

Hey there all..

	Does anyone have the source code to a good polygon 
	clipping algorithm.  This is to be used with borland's
	turbo-c (2.0)  Any help will be appreciated!!

	_Tanx_in_advance_


	-Howie		AKA: Howard H Daffin III

+------------------------------------------------------------------+
|   /  /  ____ _  _  _  ___  ____>  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|
|  /==/  / * / \ / \ /  /   /__>    + hdaffin@oucsace.cs.OHIOU.EDU+|
| /  /  /___/   /   / _/_  /____>   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|
+------------------------------------------------------------------+
| - Soon, we will see given some time that:                        |
| - Computers are an empirical representation of the mind - ;>)    |
+__________________________________________________________________+

cm26+@andrew.cmu.edu (Curt McDowell) (05/03/89)

The following is a package which maintains polygons and includes a
routine to clip polygons to a rectangle.  It is written in an
object-oriented style.  It works quite well.  The first file is an
example of how you'd put it to use, the second is a simple definition of
a viewport (clipping rectangle), the third is the polygon header file to
be included by other modules, and the fourth is the polygon code file.

Curt McDowell
Carnegie Mellon University

--- FILE EXAMPLE.C ---
#include <stdio.h>
#include <polygon.h>
#include <viewport.h>

main(argc, argv)
char **argv;
{
    struct polygon *p;
    struct viewport v;

    p = polygon_New();

    polygon_Insert(p, 10, 100);
    polygon_Insert(p, ..., ...);
    ... etc ...;

    v.left = 1;
    v.top = ...;
    v.width = ...;
    v.height = ...;

    polygon_Clip(p, &v);

    printf("Clipped polygon:\n");

    for (i = 0; i < p->n; i++)
        printf("(%d,%d)\n", p->x[i], p->y[i]);
}

--- FILE VIEWPORT.H ---
struct viewport {
    int left, top;
    int width, height;
};
--- FILE POLYGON.H ---
/*
 * Polygon data structure
 */

struct polygon {
    short n, alloc;
    short *x, *y;
};

#define polygon_Clear(p) ((p)->n = 0)

extern struct polygon *polygon_New();
extern void polygon_Insert();
extern void polygon_Destroy();
extern void polygon_Clip();
--- FILE POLYGON.C ---
/*
 * Polygon object
 * by Curt McDowell, CMU Information Technology Center
 *
 * This code comes under the IBM Copyright of the Andrew Toolkit,
 * which is to say, you can do anything but sell it.
 */

#include <polygon.h>
#include <viewport.h>

char *malloc(), *realloc();

/* Similar triangle macro:
 * Given three coordinates along axis 1 and two
 * along axis 2, finds the third on axis 2 which
 * falls between the two on axis 1. */

#define ClipCase(left, middle, right, start, end) \
     (((start) * ((right) - (middle)) + \
       (end) * ((middle) - (left))) / ((right) - (left)))

/* Polygon manipulation:
 * Dynamically allocated polygon structure
 * Use this to create and destroy polygons to be
 * passed to the clipping and filling routines. */

struct polygon *polygon_New()
{
    struct polygon *p;
    p = (struct polygon *) malloc(sizeof (struct polygon));
    p->alloc = 8;
    p->x = (short *) malloc(p->alloc * sizeof (short));
    p->y = (short *) malloc(p->alloc * sizeof (short));
    p->n = 0;
    return p;
}

void polygon_Insert(p, x, y)
struct polygon *p;
short x, y;
{
    if (p->n == p->alloc) {
        p->alloc *= 2;
        p->x = (short *) realloc(p->x, p->alloc * sizeof (short));
        p->y = (short *) realloc(p->y, p->alloc * sizeof (short));
    }
    p->x[p->n] = x;
    p->y[p->n] = y;
    p->n++;
}

void polygon_Destroy(p)
struct polygon *p;
{
    free(p->x);
    free(p->y);
    free(p);
}

/*
 * Clip Polygon associated code
 */

#define edge_LEFT       0
#define edge_RIGHT      1
#define edge_ABOVE      2
#define edge_BELOW      3

static short Inside(x, y, v, which)
short x, y;
struct viewport *v;
short which;
{
    switch (which) {
        case edge_ABOVE:
            return (y >= v->top);
        case edge_BELOW:
            return (y < v->top + v->height);
        case edge_LEFT:
            return (x >= v->left);
        case edge_RIGHT:
            return (x < v->left + v->width);
    }
}

static void Intersect(px, py, fx, fy, tx, ty, v, which)
short *px, *py;
short fx, fy, tx, ty;
struct viewport *v;
short which;
{
    switch (which) {
        case edge_ABOVE:
            *py = v->top;
            *px = ClipCase(fy, *py, ty, fx, tx);
            break;
        case edge_BELOW:
            *py = v->top + v->height - 1;
            *px = ClipCase(fy, *py, ty, fx, tx);
            break;
        case edge_LEFT:
            *px = v->left;
            *py = ClipCase(fx, *px, tx, fy, ty);
            break;
        case edge_RIGHT:
            *px = v->left + v->width - 1;
            *py = ClipCase(fx, *px, tx, fy, ty);
            break;
    }
}

static void ClipEdge(in, out, v, which)
struct polygon *in, *out;
struct viewport *v;
short which;
{
    short i, ix, iy;

    i = 0;
    out->n = 0;

    do {
        /* case I loop as long as inside */
        while (i < in->n && Inside(in->x[i], in->y[i], v, which)) {
            polygon_Insert(out, in->x[i], in->y[i]);
            i++;
        }
        if (i < in->n) {
            /* case II unless first point is outside */
            if (i > 0) {
                Intersect(&ix, &iy, in->x[i - 1], in->y[i - 1],
                                    in->x[i], in->y[i], v, which);
                polygon_Insert(out, ix, iy);
            }
            /* case III loop as long as outside */
            while (i < in->n && ! Inside(in->x[i], in->y[i], v, which))
                i++;
            /* case IV outside to inside */
            if (i < in->n) {
                Intersect(&ix, &iy, in->x[i - 1], in->y[i - 1],
                                    in->x[i], in->y[i], v, which);
                polygon_Insert(out, ix, iy);
            }
        }
    } while (i < in->n);

    /* Now check if there's a crossing between the last & first points */

    if (Inside(in->x[in->n - 1], in->y[in->n - 1], v, which) ^
        Inside(in->x[0], in->y[0], v, which)) {
        Intersect(&ix, &iy, in->x[in->n - 1], in->y[in->n - 1],
                            in->x[0], in->y[0], v, which);
        polygon_Insert(out, ix, iy);
    }
}

void polygon_Clip(p, v)
struct polygon *p;
struct viewport *v;
{
    static struct polygon *t = 0;  /* temporary polygon, stays around */

    if (t == 0)
        t = polygon_New();
    else
        t->n = 0;

    ClipEdge(p, t, v, edge_ABOVE);
    ClipEdge(t, p, v, edge_BELOW);
    ClipEdge(p, t, v, edge_LEFT);
    ClipEdge(t, p, v, edge_RIGHT);
}