1 /* Copyright (C) 1992-1998 The Geometry Center
2  * Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips
3  *
4  * This file is part of Geomview.
5  *
6  * Geomview is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published
8  * by the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * Geomview is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with Geomview; see the file COPYING.  If not, write
18  * to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
19  * USA, or visit http://www.gnu.org.
20  */
21 
22 #if 0
23 static char copyright[] = "Copyright (C) 1992-1998 The Geometry Center\n\
24 Copyright (C) 1998-2000 Stuart Levy, Tamara Munzner, Mark Phillips";
25 #endif
26 
27 /*
28  * Clipping routine.
29  * Adapted from Daeron Meyer's Ginsu.
30  * by Dan Krech and Stuart Levy, Geometry Center, 1994.
31  */
32 
33 #include "Clip.h"
34 
35 #define EPS 0.00001
36 
add_vertex(Clip * clip,vertex_list * vtxl,float * aCoord,Color * c)37 vertex *add_vertex(Clip *clip, vertex_list *vtxl, float *aCoord, Color *c)
38 {
39   vertex *head = vtxl->head;
40   vertex *temp = head;
41 
42   head = (vertex *)malloc(sizeof(vertex));
43   head->coord = (float *)malloc((clip->dim+1)*sizeof(float));
44 
45   head->next = temp;
46   memcpy(head->coord, aCoord, clip->dim*sizeof(float));
47 
48   head->c = *c;
49   head->clip = 0;
50   vtxl->head = head;
51   return (head);
52 }
53 
find_unclipped_vertex(polyvtx_list * me,vertex ** vertex_set)54 int find_unclipped_vertex(polyvtx_list *me,vertex **vertex_set)
55 {
56   pvtx *temp = me->head;
57   pvtx *point;
58   int brk=0;
59 
60   point = me->head;
61 
62   do {
63    brk = vertex_set[point->num]->clip;	/* Check polygon vertex list to see */
64    if (brk)				/* if any still remain */
65      point = point->next;
66   } while (brk && (point != temp));
67 
68   if ((point == temp) && brk)		/* if we found a vertex, return 1 */
69     return 1;
70 
71   me->head = point;
72   return 0;				/* otherwise return 0 */
73 }
74 
75 
dot(Clip * clip,float * point)76 float dot(Clip *clip, float *point)
77 {
78     int i;
79     int dim = clip->dim;
80     float sum = clip->surf[dim];
81 
82     for(i=0;i<dim;i++) {
83         sum += point[i] * clip->surf[i];
84     }
85     return sum;
86 }
87 
pcinterp(Clip * clip,float * result,float * p1,float * p2,Color * cresult,Color * c1,Color * c2,float val1,float val2)88 void pcinterp(Clip *clip, float *result, float *p1, float *p2, Color *cresult, Color *c1, Color *c2, float val1, float val2)
89 {
90     int i;
91     int dim = clip->dim;
92     float t = val1 / (val1 - val2);
93     float unt;
94     float val;
95 
96     /* Don't go too crazy in case of numerical error. */
97     if(t < 0) t = 0;
98     else if(t > 1) t = 1;
99     unt = 1 - t;
100 
101     for(i=dim; --i >= 0; )
102         result[i] = p1[i]*unt + p2[i]*t;
103     if(clip->nonlinear) {
104 	float eps = EPS * fabs(val1 - val2);
105 	int limit = 7;
106 	float t1 = 0, t2 = 1, a;
107 
108 	for(;;) {
109 	    val = (*clip->clipfunc)(clip, result) - clip->level;
110 	    if(fabs(val) < eps || --limit <= 0)
111 		break;
112 	    if(val * val1 < 0) {
113 		t2 = t;
114 		val2 = val;
115 	    } else {
116 		t1 = t;
117 		val1 = val;
118 	    }
119 	    a = val1 / (val1 - val2);	/*Subdivide interval */
120 	    t = (1-a)*t1 + a*t2;	/*Transform back to original interval*/
121 	    unt = 1-t;
122 	    for(i=dim; --i >= 0; )
123 		result[i] = p1[i]*unt + p2[i]*t; /* Interpolate point */
124 	}
125     }
126     cresult->r = c1->r*unt + c2->r*t;
127     cresult->g = c1->g*unt + c2->g*t;
128     cresult->b = c1->b*unt + c2->b*t;
129 }
130 
clip_each_vertex(Clip * clip,polyvtx_list * me,vertex_list * vtxl,vertex ** vertex_set)131 int clip_each_vertex(Clip *clip, polyvtx_list *me, vertex_list *vtxl, vertex **vertex_set)
132 {
133   pvtx *temp, *next, *last;
134   float intersect[MAXDIM];
135 
136   Color c, *c1, *c2;
137 
138   float *p1 = NULL;
139   float *p2 = NULL;
140   vertex *v1, *v2;
141 
142   last = me->head;
143 
144   me->point = me->head;
145   me->point->me = vertex_set[me->point->num];
146 
147   do
148   {
149     next = me->point->next;
150     next->me = vertex_set[next->num];
151 
152     v1 = vertex_set[me->point->num];
153     v2 = vertex_set[next->num];
154 
155     c1 = &v1->c;	/* Color of current vertex */
156     c2 = &v2->c;	/* Color of next vertex */
157 
158     p1 = v1->coord;
159     p2 = v2->coord;		/* Coordinates of next vtx */
160 
161     /*
162      * Handle first case:
163      *
164      *
165      *            o--------o <---- next vertex
166      *           /        /
167      *         /         /            side to clip
168      *      -------------------------------  <------- clipping plane
169      *      /          /
170      *    /           /
171      *   o-----------o   <--- current vertex
172      */
173 
174     if (!v1->clip && v2->clip)
175     {
176 	/* Calculate where line between the two points cuts clipping surface */
177 	pcinterp(clip, intersect, p1, p2, &c,c1,c2, v1->val, v2->val);
178 
179 	temp = (pvtx *)malloc(sizeof(pvtx));  	/* Add vertex at intersection */
180 
181         temp->me = add_vertex(clip, vtxl, intersect, &c);
182         me->numvtx++;				/* point to the polygon's */
183         temp->next = next;			/* vertex list. */
184         me->point->next = temp;
185         last = temp;
186         me->point = next;
187         next = me->point->next;
188     }
189     else
190 
191     /*
192      * Handle second case:
193      *
194      *
195      * next vertex ->   o--------o <---- current vertex
196      *                 /        /
197      *               /         /            side to clip
198      *             /          /
199      *    -------------------o-----------------  <------- clipping plane
200      *          /           /
201      *        /            /
202      *       o------------o
203      */
204 
205       if (v1->clip && v2->clip)
206       {
207         last->next = next;			/* simply delete the current */
208 
209         free(me->point);
210 	me->point = NULL;
211 
212         me->numvtx--;
213         me->point = next;
214         next = me->point->next;
215       }
216     else
217 
218     /*
219      * Handle third case:
220      *
221      *
222      *                  o--------o <- current vertex
223      *                 /        /
224      *               /         /            side to clip
225      *             /          /
226      *    -------------------------------------  <------- clipping plane
227      *          /           /
228      *        /            /
229      *       o------------o <- next vertex
230      */
231 
232       if (v1->clip && !v2->clip)
233       {
234 	pcinterp(clip, intersect, p1, p2, &c, c1, c2, v1->val, v2->val);
235 
236     	temp = (pvtx *)malloc(sizeof(pvtx));	/* Add vertex at the */
237 
238 	temp->me = add_vertex(clip, vtxl, intersect, &c);
239 	temp->next = next;			/* intersection point to the */
240 	last->next = temp;			/* polygon's vertex list */
241 
242 	free(me->point);
243 	me->point = NULL;
244 
245 	last = temp;				/* from the list. */
246 	me->point = next;
247 	next = me->point->next;
248      }						/* fourth case: */
249      else					/* Both vertices unclipped. */
250        {					/* Therefore, do nothing. */
251          last = me->point;
252          me->point = next;
253          next = me->point->next;
254        }
255 
256   } while (me->point != me->head);		/* Do this 'til we have */
257 						/* checked all vertices in */
258 						/* the circular linked list. */
259 
260   return me->numvtx;
261 
262 }
263 
264 
clip_init(Clip * clip)265 void clip_init(Clip *clip)
266 {
267     clip->polyhedron.numpoly = 0;
268     clip->polyhedron.head = NULL;
269     clip->polyhedron.has = 0;
270 
271     clip->polyvertex.numvtx = 0;
272     clip->polyvertex.head = NULL;
273 
274     clip->side = CLIP_LE;
275     clip->level = 0.0;
276 
277     clip->clipfunc = dot;
278 }
279 
clip_destroy(Clip * clip)280 void clip_destroy(Clip *clip)
281 {
282 #ifdef notyet
283     poly *po, *nextpo;
284     vertex *v, *nextv;
285 
286     for(po = clip->polyhedron.head; po != NULL; po = nextpo) {
287 	nextpo = po->next;
288 	free(po);
289     }
290     for(v = clip->polyvertex.head; v != NULL; v = nextv) {
291 	nextv = v->next;
292 	free(v);
293     }
294 #endif
295     clip->polyhedron.numpoly = 0;
296     clip->polyhedron.head = NULL;
297     clip->polyhedron.has = 0;
298 
299     clip->polyvertex.numvtx = 0;
300     clip->polyvertex.head = NULL;
301 }
302 
setClipPlane(Clip * clip,float * coeff,float level)303 void setClipPlane(Clip *clip, float *coeff, float level)
304 {
305     memcpy(clip->surf, coeff, MAXDIM * sizeof(float));
306     clip->level = level;
307 }
308 
setSide(Clip * clip,int side)309 void setSide(Clip *clip, int side)
310 {
311     clip->side = side;
312 }
313 
clip_vertices(Clip * clip)314 void clip_vertices(Clip *clip)
315 {
316   vertex *point;
317 
318   for(point = clip->polyvertex.head; point != NULL; point = point->next) {
319     point->val = (*clip->clipfunc)(clip, point->coord) - clip->level;
320 
321     point->clip = (clip->side == CLIP_LE) ?
322 			(point->val > -EPS) : (point->val < EPS);
323   }
324 }
325 
326 /* Find the range of function values over all vertices */
span_vertices(Clip * clip,float * minp,float * maxp)327 int span_vertices(Clip *clip, float *minp, float *maxp)
328 {
329   vertex *point;
330   float min, max, val;
331 
332   *minp = *maxp = 0;
333   point = clip->polyvertex.head;
334   if(point == NULL)
335     return 0;
336   min = max = (*clip->clipfunc)(clip, point->coord);
337   for(point = clip->polyvertex.head; point != NULL; point = point->next) {
338     val = (*clip->clipfunc)(clip, point->coord);
339     if(clip->side != CLIP_LE)
340 	val = -val;
341     if(min > val) min = val;
342     else if(max < val) max = val;
343   }
344   *minp = min;
345   *maxp = max;
346   return 1;
347 }
348 
349 
clip_polygons(Clip * clip,vertex_list * vtxl)350 void clip_polygons(Clip *clip, vertex_list *vtxl)
351 {
352     poly *point;
353 
354     vertex **vertex_set;
355 
356     vertex_set = (vertex **)malloc(vtxl->numvtx * sizeof(vertex));
357 
358     {
359         int count = 0;
360 	vertex *vert;
361         vert = vtxl->head;
362         while(vert!=NULL) {
363             vertex_set[count] = vert;
364 	    vert = vert->next;
365   	    count++;
366 	}
367     }
368 
369     point = clip->polyhedron.head;
370     clip->polyhedron.point = point;
371     while (point!=NULL) {
372         point->clipped = find_unclipped_vertex(point->me, vertex_set);
373 
374 	if(!point->clipped) {
375 	    point->numvtx = clip_each_vertex(clip, point->me, vtxl, vertex_set);
376 	}
377 
378         point = point->next;			/* the list. */
379     }
380     clip->polyhedron.point = point;
381 }
382 
383 
refresh_vertex_list(Clip * clip,vertex_list * vtxl)384 void refresh_vertex_list(Clip *clip, vertex_list *vtxl)
385 {
386   int count = 0;
387 
388   vtxl->point = vtxl->head;
389   while (vtxl->point != NULL) {
390     if (!vtxl->point->clip) {
391 	vtxl->point->num = count;	/* Count number of vertices remaining */
392 	count++;			/* after clip and give each vertex a */
393     }					/* new reference number. */
394     vtxl->point = vtxl->point->next;
395   }
396   vtxl->numvtx = count;
397 }
398 
refresh_poly_list(Clip * clip,poly_list * pl)399 void refresh_poly_list(Clip *clip, poly_list *pl)
400 {
401   int count = 0;
402   poly *point;
403   point = pl->head;
404   while (point != NULL) {
405     if (!point->clipped)		/* Count number of polygons remaining */
406       count++;				/* after clip. */
407     point=point->next;
408   }
409   pl->numpoly = count;
410 }
411 
do_clip(Clip * clip)412 void do_clip(Clip *clip)
413 {
414   if(clip->polyvertex.numvtx!=0) {
415     clip_vertices(clip); 	    /* mark appropriate vertices as clipped */
416     clip_polygons(clip, &clip->polyvertex);  /* modify or remove clipped polygons */
417     refresh_vertex_list(clip, &clip->polyvertex);
418 				    /* rearrange pointers into vertex list */
419     refresh_poly_list(clip, &clip->polyhedron);
420 				    /* rearrange points into polygon list */
421   }
422 }
423 
424