#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define X 400
#define Y 400
#define BG BLACK
#define WORK WHITE
#define S CYAN
#define C GREEN
#define POLY RED
typedef struct _node
{
int x, y;
struct _node *next;
struct _node *prev;
struct _node *nextPoly;
/* pointer to the next polygon */
struct _node *neighbor;
/* the coresponding intersection point */
int intersect;
/* 1 if an intersection point, 0 otherwise */
int entry;
/* 1 if an entry point, 0 otherwise */
int visited;
/* 1 if the node has been visited, 0 otherwise */
float alpha;
/* intersection point placemet */
} node;
****************************************************************************
/* module clip.c */
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include "libsx.h"
#include "node.h"
node *s=0, *c=0, *root=0;
int DRAW=1, CLIP=1, pS=1, pC=1;
Widget W[8];
void view_node(node *p)
{
if(p) printf("%c%c%c (%3d,%3d)
%f c:%10p n:%10p P:%10p\n",
p->intersect ? 'I' : ' ',
p->entry ? 'E' : ' ',
p->visited ? 'X' : ' ',
p->x, p->y, p->alpha, p, p->neighbor, p->nextPoly);
else puts("NULL");
}
void view(node *p)
{
node *aux=p;
puts("");
if(aux) do
{
view_node(aux);
aux=aux->next;
}
while(aux && aux !=
p);
}
void plot(node *p)
{
node *aux=p;
SetColor(WORK);
if(aux) do
{
DrawLine(aux->x-2, aux->y, aux->x+2, aux->y);
DrawLine(aux->x, aux->y-2, aux->x, aux->y+2);
aux=aux->next;
}
while(aux && aux !=
p);
}
void delete(node *p)
{
node *aux, *hold;
if(hold=p) do
{
aux=p;
p=p->next;
free(aux);
}
while(p && p!=hold);
}
void insert(node *ins, node *first,
node *last)
{
node *aux=first;
while(aux != last &&
aux->alpha < ins->alpha) aux = aux->next;
ins->next = aux;
ins->prev = aux->prev;
ins->prev->next = ins;
ins->next->prev = ins;
}
node *create(int x, int y, node *next,
node *prev, node *nextPoly,
node *neighbor, int intersect,
int entry, int visited, float alpha)
{
node *new = malloc(sizeof(node));
new->x = x;
new->y = y;
new->next = next;
new->prev = prev;
if(prev) new->prev->next =
new;
if(next) new->next->prev =
new;
new->nextPoly = nextPoly;
new->neighbor = neighbor;
new->intersect = intersect;
new->entry = entry;
new->visited = visited;
new->alpha = alpha;
return new;
}
node *next_node(node *p)
{
node *aux=p;
while(aux && aux->intersect)
aux=aux->next;
return aux;
}
node *last_node(node *p)
{
node *aux=p;
if(aux) while(aux->next) aux=aux->next;
return aux;
}
node *first(node *p)
{
node *aux=p;
if (aux)
do aux=aux->next;
while(aux!=p && (!aux->intersect
|| aux->intersect && aux->visited));
return aux;
}
void circle(node *p)
{
node *aux = last_node(p);
aux->prev->next = p;
p->prev = aux->prev;
free(aux);
}
float dist(float x1, float y1, float
x2, float y2)
{
return sqrt((x1-x2)*(x1-x2)
+ (y1-y2)*(y1-y2));
}
I(node *p1, node *p2, node *q1, node
*q2,
float *alpha_p, float *alpha_q,
int *xint, int *yint)
{
float x, y, tp, tq, t, par;
par = (float) ((p2->x - p1->x)*(q2->y
- q1->y) -
(p2->y - p1->y)*(q2->x - q1->x));
if (!par) return 0; /* parallel lines */
tp = ((q1->x - p1->x)*(q2->y
- q1->y) - (q1->y - p1->y)*(q2->x - q1->x))/par;
tq = ((p2->y - p1->y)*(q1->x
- p1->x) - (p2->x - p1->x)*(q1->y - p1->y))/par;
if(tp<0 || tp>1 || tq<0 || tq>1) return 0;
x = p1->x + tp*(p2->x - p1->x);
y = p1->y + tp*(p2->y - p1->y);
*alpha_p = dist(p1->x, p1->y,
x, y) / dist(p1->x, p1->y, p2->x, p2->y);
*alpha_q = dist(q1->x, q1->y,
x, y) / dist(q1->x, q1->y, q2->x, q2->y);
*xint = (int) x;
*yint = (int) y;
return 1;
}
int test(node *point, node *p)
{
node *aux, *left, i;
int type=0;
left = create(0, point->y, 0,
0, 0, 0, 0, 0, 0, 0.);
for(aux=p; aux->next; aux=aux->next)
if(I(left, point, aux, aux->next,
&i.alpha, &i.alpha, &i.x, &i.y)) type++;
return type%2;
}
void quit(Widget w, void *p)
{
delete(s);
delete(c);
exit(0);
}
void redisplay(Widget w, int x, int
y, void *p)
{
node *aux, *poly;
ClearDrawArea();
if (aux=s)
{
SetColor(DRAW==1 ? WORK:S);
while (aux->next && aux->next != s)
{
DrawLine(aux->x, aux->y, aux->next->x, aux->next->y);
aux = aux->next;
}
if(DRAW!=1) DrawLine(aux->x, aux->y, s->x, s->y);
}
if (aux=c)
{
SetColor(DRAW==2 ? WORK:C);
while (aux->next && aux->next != c)
{
DrawLine(aux->x, aux->y, aux->next->x, aux->next->y);
aux = aux->next;
}
if(DRAW!=2) DrawLine(aux->x, aux->y, c->x, c->y);
}
if (root)
{
SetColor(POLY);
for(poly = root; poly; poly = poly->nextPoly)
{
for(aux = poly; aux->next; aux = aux->next)
DrawLine(aux->x, aux->y, aux->next->x, aux->next->y);
DrawLine(aux->x, aux->y, ((node *)poly)->x, ((node *)poly)->y);
}
plot(s);
plot(c);
}
}
void clip(Widget w, void *p)
{
node *auxs, *auxc, *is, *ic;
int xi, yi, e;
float alpha_s, alpha_c;
node *crt, *new, *old;
int forward;
if(DRAW || !CLIP || !s || !c) return;
auxs = last_node(s);
create(s->x, s->y, 0, auxs,
0, 0, 0, 0, 0, 0.);
auxc = last_node(c);
create(c->x, c->y, 0, auxc,
0, 0, 0, 0, 0, 0.);
for(auxs = s; auxs->next; auxs
= auxs->next)
if(!auxs->intersect)
for(auxc = c; auxc->next; auxc
= auxc->next)
if(!auxc->intersect)
if(I(auxs, next_node(auxs->next),
auxc, next_node(auxc->next),
&alpha_s, &alpha_c, &xi, &yi))
{
is = create(xi, yi, 0, 0, 0, 0, 1, 0, 0, alpha_s);
ic = create(xi, yi, 0, 0, 0, 0, 1, 0, 0, alpha_c);
is->neighbor = ic;
ic->neighbor = is;
insert(is, auxs, next_node(auxs->next));
insert(ic, auxc, next_node(auxc->next));
}
e = test(s, c);
if(pS) e = 1-e;
for(auxs = s; auxs->next; auxs
= auxs->next)
if(auxs->intersect)
{
auxs->entry = e;
e = 1-e;
}
e=test(c, s);
if(pC) e = 1-e;
for(auxc = c; auxc->next; auxc
= auxc->next)
if(auxc->intersect)
{
auxc->entry = e;
e = 1-e;
}
circle(s);
circle(c);
while ((crt = first(s)) !=
s)
{
old = 0;
for(; !crt->visited; crt = crt->neighbor)
for(forward = crt->entry ;; )
{
new = create(crt->x, crt->y, old, 0, 0, 0, 0, 0, 0, 0.);
old = new;
crt->visited = 1;
crt = forward ? crt->next : crt->prev;
if(crt->intersect)
{
crt->visited = 1;
break;
}
}
old->nextPoly = root;
root = old;
}
view(s);
view(c);
redisplay(W[3], X, Y, NULL);
CLIP=0;
}
void add(Widget w, int which_button,
int x, int y, void *data)
{
node *new;
if (!DRAW) return;
if (which_button == 1)
{
new = malloc(sizeof(node));
new->x = x;
new->y = y;
new->prev = 0; /* not need to
initialize with 0 after malloc ... */
new->nextPoly = 0;
new->neighbor = 0;
new->intersect = 0;
new->entry = 0;
new->visited = 0;
new->alpha = 0.;
if (DRAW == 1)
{
new->next = s;
if (s) s->prev = new;
s = new;
}
else /* DRAW == 2 */
{
new->next = c;
if (c) c->prev = new;
c = new;
}
redisplay(W[3], X, Y, NULL);
}
else if (which_button == 3)
{
DRAW = DRAW==1 ? 2:0;
redisplay(W[3], X, Y, NULL);
}
}
void set(Widget w, char *c)
{
pS=0; pC=0;
if(*c==65 || *c==68) pS=1;
if(*c==65 || *c==67) pC=1;
}
void display(int argc, char **argv)
{
if (OpenDisplay(argc, argv)
== FALSE) return;
W[0] = MakeMenu("Func");
W[1] = MakeButton("Clip", clip,
NULL);
W[2] = MakeButton("Quit", quit,
NULL);
W[3] = MakeDrawArea(X, Y, redisplay,
NULL);
W[4] = MakeMenuItem(W[0], "A&B
", (ButtonCB) set, "A");
W[5] = MakeMenuItem(W[0], "A|B
", (ButtonCB) set, "B");
W[6] = MakeMenuItem(W[0], "A/B
", (ButtonCB) set, "C");
W[7] = MakeMenuItem(W[0], "B/A
", (ButtonCB) set, "D");
SetWidgetPos(W[1], PLACE_RIGHT,
W[0], NO_CARE, NULL);
SetWidgetPos(W[2], PLACE_RIGHT,
W[1], NO_CARE, NULL);
SetWidgetPos(W[3], PLACE_UNDER,
W[0], NO_CARE, NULL);
SetButtonDownCB(W[3], add);
ShowDisplay();
GetStandardColors();
SetBgColor(W[3], BG);
}
main(int argc, char **argv)
{
display(argc, argv);
MainLoop();
}