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