3 * Mesa 3-D graphics library
5 * Copyright (C) 1995-2000 Brian Paul
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * This file is part of the polygon tesselation code contributed by
40 static GLenum
store_polygon_as_contour(GLUtriangulatorObj
*);
41 static void free_current_polygon(tess_polygon
*);
42 static void prepare_projection_info(GLUtriangulatorObj
*);
43 static GLdouble
twice_the_polygon_area(tess_vertex
*, tess_vertex
*);
44 static GLenum
verify_edge_vertex_intersections(GLUtriangulatorObj
*);
45 void tess_find_contour_hierarchies(GLUtriangulatorObj
*);
46 static GLenum
test_for_overlapping_contours(GLUtriangulatorObj
*);
47 static GLenum
contours_overlap(tess_contour
*, tess_polygon
*);
48 static GLenum
is_contour_contained_in(tess_contour
*, tess_contour
*);
49 static void add_new_exterior(GLUtriangulatorObj
*, tess_contour
*);
50 static void add_new_interior(GLUtriangulatorObj
*, tess_contour
*,
52 static void add_interior_with_hierarchy_check(GLUtriangulatorObj
*,
53 tess_contour
*, tess_contour
*);
54 static void reverse_hierarchy_and_add_exterior(GLUtriangulatorObj
*,
57 static GLboolean
point_in_polygon(tess_contour
*, GLdouble
, GLdouble
);
58 static void shift_interior_to_exterior(GLUtriangulatorObj
*, tess_contour
*);
59 static void add_exterior_with_check(GLUtriangulatorObj
*, tess_contour
*,
61 static GLenum
cut_out_hole(GLUtriangulatorObj
*, tess_contour
*,
63 static GLenum
merge_hole_with_contour(GLUtriangulatorObj
*,
64 tess_contour
*, tess_contour
*,
65 tess_vertex
*, tess_vertex
*);
68 find_normal(GLUtriangulatorObj
* tobj
)
70 tess_polygon
*polygon
= tobj
->current_polygon
;
71 tess_vertex
*va
, *vb
, *vc
;
73 GLdouble A0
, A1
, A2
, B0
, B1
, B2
;
75 va
= polygon
->vertices
;
77 A0
= vb
->location
[0] - va
->location
[0];
78 A1
= vb
->location
[1] - va
->location
[1];
79 A2
= vb
->location
[2] - va
->location
[2];
80 for (vc
= vb
->next
; vc
!= va
; vc
= vc
->next
) {
81 B0
= vc
->location
[0] - va
->location
[0];
82 B1
= vc
->location
[1] - va
->location
[1];
83 B2
= vc
->location
[2] - va
->location
[2];
84 A
= A1
* B2
- A2
* B1
;
85 B
= A2
* B0
- A0
* B2
;
86 C
= A0
* B1
- A1
* B0
;
87 if (fabs(A
) > EPSILON
|| fabs(B
) > EPSILON
|| fabs(C
) > EPSILON
) {
92 -A
* va
->location
[0] - B
* va
->location
[1] - C
* va
->location
[2];
96 tess_call_user_error(tobj
, GLU_TESS_ERROR7
);
101 tess_test_polygon(GLUtriangulatorObj
* tobj
)
103 tess_polygon
*polygon
= tobj
->current_polygon
;
105 /* any vertices defined? */
106 if (polygon
->vertex_cnt
< 3) {
107 free_current_polygon(polygon
);
111 polygon
->last_vertex
->next
= polygon
->vertices
;
112 polygon
->vertices
->previous
= polygon
->last_vertex
;
113 /* determine the normal */
114 if (find_normal(tobj
) == GLU_ERROR
)
116 /* compare the normals of previously defined contours and this one */
117 /* first contour define ? */
118 if (tobj
->contours
== NULL
) {
119 tobj
->A
= polygon
->A
;
120 tobj
->B
= polygon
->B
;
121 tobj
->C
= polygon
->C
;
122 tobj
->D
= polygon
->D
;
123 /* determine the best projection to use */
124 if (fabs(polygon
->A
) > fabs(polygon
->B
))
125 if (fabs(polygon
->A
) > fabs(polygon
->C
))
126 tobj
->projection
= OYZ
;
128 tobj
->projection
= OXY
;
129 else if (fabs(polygon
->B
) > fabs(polygon
->C
))
130 tobj
->projection
= OXZ
;
132 tobj
->projection
= OXY
;
136 tess_vertex
*vertex
= polygon
->vertices
;
145 /* compare the normals */
146 if (fabs(a
[1] * b
[2] - a
[2] * b
[1]) > EPSILON
||
147 fabs(a
[2] * b
[0] - a
[0] * b
[2]) > EPSILON
||
148 fabs(a
[0] * b
[1] - a
[1] * b
[0]) > EPSILON
) {
150 tess_call_user_error(tobj
, GLU_TESS_ERROR9
);
153 /* the normals are parallel - test for plane equation */
154 if (fabs(a
[0] * vertex
->location
[0] + a
[1] * vertex
->location
[1] +
155 a
[2] * vertex
->location
[2] + tobj
->D
) > EPSILON
) {
156 /* not the same plane */
157 tess_call_user_error(tobj
, GLU_TESS_ERROR9
);
161 prepare_projection_info(tobj
);
162 if (verify_edge_vertex_intersections(tobj
) == GLU_ERROR
)
164 if (test_for_overlapping_contours(tobj
) == GLU_ERROR
)
166 if (store_polygon_as_contour(tobj
) == GLU_ERROR
)
171 test_for_overlapping_contours(GLUtriangulatorObj
* tobj
)
173 tess_contour
*contour
;
174 tess_polygon
*polygon
;
176 polygon
= tobj
->current_polygon
;
177 for (contour
= tobj
->contours
; contour
!= NULL
; contour
= contour
->next
)
178 if (contours_overlap(contour
, polygon
) != GLU_NO_ERROR
) {
179 tess_call_user_error(tobj
, GLU_TESS_ERROR5
);
186 store_polygon_as_contour(GLUtriangulatorObj
* tobj
)
188 tess_polygon
*polygon
= tobj
->current_polygon
;
189 tess_contour
*contour
= tobj
->contours
;
191 /* the first contour defined */
192 if (contour
== NULL
) {
193 if ((contour
= (tess_contour
*) malloc(sizeof(tess_contour
))) == NULL
) {
194 tess_call_user_error(tobj
, GLU_OUT_OF_MEMORY
);
195 free_current_polygon(polygon
);
198 tobj
->contours
= tobj
->last_contour
= contour
;
199 contour
->next
= contour
->previous
= NULL
;
202 if ((contour
= (tess_contour
*) malloc(sizeof(tess_contour
))) == NULL
) {
203 tess_call_user_error(tobj
, GLU_OUT_OF_MEMORY
);
204 free_current_polygon(polygon
);
207 contour
->previous
= tobj
->last_contour
;
208 tobj
->last_contour
->next
= contour
;
209 tobj
->last_contour
= contour
;
210 contour
->next
= NULL
;
212 /* mark all vertices in new contour as not special */
213 /* and all are boundary edges */
216 GLuint vertex_cnt
, i
;
218 for (vertex
= polygon
->vertices
, i
= 0, vertex_cnt
=
219 polygon
->vertex_cnt
; i
< vertex_cnt
; vertex
= vertex
->next
, i
++) {
220 vertex
->shadow_vertex
= NULL
;
221 vertex
->edge_flag
= GL_TRUE
;
224 contour
->vertex_cnt
= polygon
->vertex_cnt
;
225 contour
->area
= polygon
->area
;
226 contour
->orientation
= polygon
->orientation
;
227 contour
->type
= GLU_UNKNOWN
;
228 contour
->vertices
= polygon
->vertices
;
229 contour
->last_vertex
= polygon
->last_vertex
;
230 polygon
->vertices
= polygon
->last_vertex
= NULL
;
231 polygon
->vertex_cnt
= 0;
232 ++(tobj
->contour_cnt
);
237 free_current_polygon(tess_polygon
* polygon
)
239 tess_vertex
*vertex
, *vertex_tmp
;
242 /* free current_polygon structures */
243 for (vertex
= polygon
->vertices
, i
= 0; i
< polygon
->vertex_cnt
; i
++) {
244 vertex_tmp
= vertex
->next
;
248 polygon
->vertices
= polygon
->last_vertex
= NULL
;
249 polygon
->vertex_cnt
= 0;
253 prepare_projection_info(GLUtriangulatorObj
* tobj
)
255 tess_polygon
*polygon
= tobj
->current_polygon
;
256 tess_vertex
*vertex
, *last_vertex_ptr
;
259 last_vertex_ptr
= polygon
->last_vertex
;
260 switch (tobj
->projection
) {
262 for (vertex
= polygon
->vertices
; vertex
!= last_vertex_ptr
;
263 vertex
= vertex
->next
) {
264 vertex
->x
= vertex
->location
[0];
265 vertex
->y
= vertex
->location
[1];
267 last_vertex_ptr
->x
= last_vertex_ptr
->location
[0];
268 last_vertex_ptr
->y
= last_vertex_ptr
->location
[1];
271 for (vertex
= polygon
->vertices
; vertex
!= last_vertex_ptr
;
272 vertex
= vertex
->next
) {
273 vertex
->x
= vertex
->location
[0];
274 vertex
->y
= vertex
->location
[2];
276 last_vertex_ptr
->x
= last_vertex_ptr
->location
[0];
277 last_vertex_ptr
->y
= last_vertex_ptr
->location
[2];
280 for (vertex
= polygon
->vertices
; vertex
!= last_vertex_ptr
;
281 vertex
= vertex
->next
) {
282 vertex
->x
= vertex
->location
[1];
283 vertex
->y
= vertex
->location
[2];
285 last_vertex_ptr
->x
= last_vertex_ptr
->location
[1];
286 last_vertex_ptr
->y
= last_vertex_ptr
->location
[2];
289 area
= twice_the_polygon_area(polygon
->vertices
, polygon
->last_vertex
);
291 polygon
->orientation
= GLU_CCW
;
292 polygon
->area
= area
;
295 polygon
->orientation
= GLU_CW
;
296 polygon
->area
= -area
;
301 twice_the_polygon_area(tess_vertex
* vertex
, tess_vertex
* last_vertex
)
309 vertex
= vertex
->next
;
310 for (; vertex
!= last_vertex
; vertex
= vertex
->next
) {
313 (vertex
->x
- x
) * (next
->y
- y
) - (vertex
->y
- y
) * (next
->x
- x
);
318 /* test if edges ab and cd intersect */
319 /* if not return GLU_NO_ERROR, else if cross return GLU_TESS_ERROR8, */
320 /* else if adjacent return GLU_TESS_ERROR4 */
322 edge_edge_intersect(tess_vertex
* a
,
323 tess_vertex
* b
, tess_vertex
* c
, tess_vertex
* d
)
325 GLdouble denom
, r
, s
;
326 GLdouble xba
, ydc
, yba
, xdc
, yac
, xac
;
334 denom
= xba
* ydc
- yba
* xdc
;
335 r
= yac
* xdc
- xac
* ydc
;
337 if (fabs(denom
) < EPSILON
) {
338 if (fabs(r
) < EPSILON
) {
340 if (fabs(xba
) < EPSILON
) {
341 /* compare the Y coordinate */
344 (fabs(a
->y
- c
->y
) < EPSILON
345 && fabs(c
->y
- b
->y
) < EPSILON
)
346 || (fabs(a
->y
- d
->y
) < EPSILON
347 && fabs(d
->y
- b
->y
) <
348 EPSILON
)) return GLU_TESS_ERROR4
;
353 (fabs(b
->y
- c
->y
) < EPSILON
354 && fabs(c
->y
- a
->y
) < EPSILON
)
355 || (fabs(b
->y
- d
->y
) < EPSILON
356 && fabs(d
->y
- a
->y
) <
357 EPSILON
)) return GLU_TESS_ERROR4
;
361 /* compare the X coordinate */
364 (fabs(a
->x
- c
->x
) < EPSILON
365 && fabs(c
->x
- b
->x
) < EPSILON
)
366 || (fabs(a
->x
- d
->x
) < EPSILON
367 && fabs(d
->x
- b
->x
) <
368 EPSILON
)) return GLU_TESS_ERROR4
;
372 (fabs(b
->x
- c
->x
) < EPSILON
373 && fabs(c
->x
- a
->x
) < EPSILON
)
374 || (fabs(b
->x
- d
->x
) < EPSILON
375 && fabs(d
->x
- a
->x
) <
376 EPSILON
)) return GLU_TESS_ERROR4
;
383 s
= (yac
* xba
- xac
* yba
) / denom
;
384 /* test if one vertex lies on other edge */
385 if (((fabs(r
) < EPSILON
|| (r
< 1.0 + EPSILON
&& r
> 1.0 - EPSILON
)) &&
386 s
> -EPSILON
&& s
< 1.0 + EPSILON
) ||
387 ((fabs(s
) < EPSILON
|| (s
< 1.0 + EPSILON
&& s
> 1.0 - EPSILON
)) &&
388 r
> -EPSILON
&& r
< 1.0 + EPSILON
)) {
389 return GLU_TESS_ERROR4
;
391 /* test for crossing */
392 if (r
> -EPSILON
&& r
< 1.0 + EPSILON
&& s
> -EPSILON
&& s
< 1.0 + EPSILON
) {
393 return GLU_TESS_ERROR8
;
399 verify_edge_vertex_intersections(GLUtriangulatorObj
* tobj
)
401 tess_polygon
*polygon
= tobj
->current_polygon
;
402 tess_vertex
*vertex1
, *last_vertex
, *vertex2
;
405 last_vertex
= polygon
->last_vertex
;
406 vertex1
= last_vertex
;
407 for (vertex2
= vertex1
->next
->next
;
408 vertex2
->next
!= last_vertex
; vertex2
= vertex2
->next
) {
409 test
= edge_edge_intersect(vertex1
, vertex1
->next
, vertex2
,
411 if (test
!= GLU_NO_ERROR
) {
412 tess_call_user_error(tobj
, test
);
416 for (vertex1
= polygon
->vertices
;
417 vertex1
->next
->next
!= last_vertex
; vertex1
= vertex1
->next
) {
418 for (vertex2
= vertex1
->next
->next
;
419 vertex2
!= last_vertex
; vertex2
= vertex2
->next
) {
420 test
= edge_edge_intersect(vertex1
, vertex1
->next
, vertex2
,
422 if (test
!= GLU_NO_ERROR
) {
423 tess_call_user_error(tobj
, test
);
435 area_compare(const void *a
, const void *b
)
437 GLdouble area1
, area2
;
439 area1
= (*((tess_contour
**) a
))->area
;
440 area2
= (*((tess_contour
**) b
))->area
;
449 tess_find_contour_hierarchies(GLUtriangulatorObj
* tobj
)
451 tess_contour
**contours
; /* dinamic array of pointers */
452 tess_contour
*tmp_contour_ptr
= tobj
->contours
;
455 GLboolean hierarchy_changed
;
458 if (tobj
->contour_cnt
< 2) {
459 tobj
->contours
->type
= GLU_EXTERIOR
;
462 if ((contours
= (tess_contour
**)
463 malloc(sizeof(tess_contour
*) * (tobj
->contour_cnt
))) == NULL
) {
464 tess_call_user_error(tobj
, GLU_OUT_OF_MEMORY
);
467 for (tmp_contour_ptr
= tobj
->contours
, cnt
= 0;
468 tmp_contour_ptr
!= NULL
; tmp_contour_ptr
= tmp_contour_ptr
->next
)
469 contours
[cnt
++] = tmp_contour_ptr
;
470 /* now sort the contours in decreasing area size order */
471 qsort((void *) contours
, (size_t) cnt
, (size_t) sizeof(tess_contour
*),
473 /* we leave just the first contour - remove others from list */
474 tobj
->contours
= contours
[0];
475 tobj
->contours
->next
= tobj
->contours
->previous
= NULL
;
476 tobj
->last_contour
= tobj
->contours
;
477 tobj
->contour_cnt
= 1;
478 /* first contour is the one with greatest area */
479 /* must be EXTERIOR */
480 tobj
->contours
->type
= GLU_EXTERIOR
;
481 tmp_contour_ptr
= tobj
->contours
;
483 for (i
= 1; i
< cnt
; i
++) {
484 hierarchy_changed
= GL_FALSE
;
485 for (tmp_contour_ptr
= tobj
->contours
;
486 tmp_contour_ptr
!= NULL
; tmp_contour_ptr
= tmp_contour_ptr
->next
) {
487 if (tmp_contour_ptr
->type
== GLU_EXTERIOR
) {
488 /* check if contour completely contained in EXTERIOR */
489 result
= is_contour_contained_in(tmp_contour_ptr
, contours
[i
]);
492 /* now we have to check if contour is inside interiors */
495 if (tmp_contour_ptr
->next
!= NULL
&&
496 tmp_contour_ptr
->next
->type
== GLU_INTERIOR
) {
497 /* for all interior, check if inside any of them */
498 /* if not inside any of interiors, its another */
500 /* or it may contain some interiors, then change */
501 /* the contained interiors to exterior ones */
502 add_interior_with_hierarchy_check(tobj
,
507 /* not in interior, add as new interior contour */
508 add_new_interior(tobj
, tmp_contour_ptr
, contours
[i
]);
510 hierarchy_changed
= GL_TRUE
;
513 /* ooops, the marked as EXTERIOR (contours[i]) is */
514 /* actually an interior of tmp_contour_ptr */
515 /* reverse the local hierarchy */
516 reverse_hierarchy_and_add_exterior(tobj
, tmp_contour_ptr
,
518 hierarchy_changed
= GL_TRUE
;
526 if (hierarchy_changed
)
527 break; /* break from for loop */
529 if (hierarchy_changed
== GL_FALSE
) {
530 /* disjoint with all contours, add to contour list */
531 add_new_exterior(tobj
, contours
[i
]);
537 /* returns GLU_INTERIOR if inner is completey enclosed within outer */
538 /* returns GLU_EXTERIOR if outer is completely enclosed within inner */
539 /* returns GLU_NO_ERROR if contours are disjoint */
541 is_contour_contained_in(tess_contour
* outer
, tess_contour
* inner
)
543 GLenum relation_flag
;
545 /* set relation_flag to relation of containment of first inner vertex */
546 /* regarding outer contour */
547 if (point_in_polygon(outer
, inner
->vertices
->x
, inner
->vertices
->y
))
548 relation_flag
= GLU_INTERIOR
;
550 relation_flag
= GLU_EXTERIOR
;
551 if (relation_flag
== GLU_INTERIOR
)
553 if (point_in_polygon(inner
, outer
->vertices
->x
, outer
->vertices
->y
))
559 point_in_polygon(tess_contour
* contour
, GLdouble x
, GLdouble y
)
561 tess_vertex
*v1
, *v2
;
562 GLuint i
, vertex_cnt
;
563 GLdouble xp1
, yp1
, xp2
, yp2
;
567 v1
= contour
->vertices
;
568 v2
= contour
->vertices
->previous
;
569 for (i
= 0, vertex_cnt
= contour
->vertex_cnt
; i
< vertex_cnt
; i
++) {
574 if ((((yp1
<= y
) && (y
< yp2
)) || ((yp2
<= y
) && (y
< yp1
))) &&
575 (x
< (xp2
- xp1
) * (y
- yp1
) / (yp2
- yp1
) + xp1
))
576 tst
= (tst
== GL_FALSE
? GL_TRUE
: GL_FALSE
);
584 contours_overlap(tess_contour
* contour
, tess_polygon
* polygon
)
586 tess_vertex
*vertex1
, *vertex2
;
587 GLuint vertex1_cnt
, vertex2_cnt
, i
, j
;
590 vertex1
= contour
->vertices
;
591 vertex2
= polygon
->vertices
;
592 vertex1_cnt
= contour
->vertex_cnt
;
593 vertex2_cnt
= polygon
->vertex_cnt
;
594 for (i
= 0; i
< vertex1_cnt
; vertex1
= vertex1
->next
, i
++) {
595 for (j
= 0; j
< vertex2_cnt
; vertex2
= vertex2
->next
, j
++)
596 if ((test
= edge_edge_intersect(vertex1
, vertex1
->next
, vertex2
,
597 vertex2
->next
)) != GLU_NO_ERROR
)
604 add_new_exterior(GLUtriangulatorObj
* tobj
, tess_contour
* contour
)
606 contour
->type
= GLU_EXTERIOR
;
607 contour
->next
= NULL
;
608 contour
->previous
= tobj
->last_contour
;
609 tobj
->last_contour
->next
= contour
;
610 tobj
->last_contour
= contour
;
614 add_new_interior(GLUtriangulatorObj
* tobj
,
615 tess_contour
* outer
, tess_contour
* contour
)
617 contour
->type
= GLU_INTERIOR
;
618 contour
->next
= outer
->next
;
619 contour
->previous
= outer
;
620 if (outer
->next
!= NULL
)
621 outer
->next
->previous
= contour
;
622 outer
->next
= contour
;
623 if (tobj
->last_contour
== outer
)
624 tobj
->last_contour
= contour
;
628 add_interior_with_hierarchy_check(GLUtriangulatorObj
* tobj
,
629 tess_contour
* outer
,
630 tess_contour
* contour
)
634 /* for all interiors of outer check if they are interior of contour */
635 /* if so, change that interior to exterior and move it of of the */
636 /* interior sequence */
637 if (outer
->next
!= NULL
&& outer
->next
->type
== GLU_INTERIOR
) {
640 for (ptr
= outer
->next
; ptr
!= NULL
&& ptr
->type
== GLU_INTERIOR
;
642 test
= is_contour_contained_in(ptr
, contour
);
645 /* contour is contained in one of the interiors */
646 /* check if possibly contained in other exteriors */
647 /* move ptr to first EXTERIOR */
648 for (; ptr
!= NULL
&& ptr
->type
== GLU_INTERIOR
; ptr
= ptr
->next
);
650 /* another exterior */
651 add_new_exterior(tobj
, contour
);
653 add_exterior_with_check(tobj
, ptr
, contour
);
656 /* one of the interiors is contained in the contour */
657 /* change it to EXTERIOR, and shift it away from the */
658 /* interior sequence */
659 shift_interior_to_exterior(tobj
, ptr
);
669 /* add contour to the interior sequence */
670 add_new_interior(tobj
, outer
, contour
);
674 reverse_hierarchy_and_add_exterior(GLUtriangulatorObj
* tobj
,
675 tess_contour
* outer
,
676 tess_contour
* contour
)
680 /* reverse INTERIORS to EXTERIORS */
682 if (outer
->next
!= NULL
&& outer
->next
->type
== GLU_INTERIOR
)
683 for (ptr
= outer
->next
; ptr
!= NULL
&& ptr
->type
== GLU_INTERIOR
;
684 ptr
= ptr
->next
) ptr
->type
= GLU_EXTERIOR
;
685 /* the outer now becomes inner */
686 outer
->type
= GLU_INTERIOR
;
687 /* contour is the EXTERIOR */
688 contour
->next
= outer
;
689 if (tobj
->contours
== outer
) {
690 /* first contour beeing reversed */
691 contour
->previous
= NULL
;
692 tobj
->contours
= contour
;
695 outer
->previous
->next
= contour
;
696 contour
->previous
= outer
->previous
;
698 outer
->previous
= contour
;
702 shift_interior_to_exterior(GLUtriangulatorObj
* tobj
, tess_contour
* contour
)
704 contour
->previous
->next
= contour
->next
;
705 if (contour
->next
!= NULL
)
706 contour
->next
->previous
= contour
->previous
;
708 tobj
->last_contour
= contour
->previous
;
712 add_exterior_with_check(GLUtriangulatorObj
* tobj
,
713 tess_contour
* outer
, tess_contour
* contour
)
717 /* this contour might be interior to further exteriors - check */
718 /* if not, just add as a new exterior */
719 for (; outer
!= NULL
&& outer
->type
== GLU_EXTERIOR
; outer
= outer
->next
) {
720 test
= is_contour_contained_in(outer
, contour
);
723 /* now we have to check if contour is inside interiors */
726 if (outer
->next
!= NULL
&& outer
->next
->type
== GLU_INTERIOR
) {
727 /* for all interior, check if inside any of them */
728 /* if not inside any of interiors, its another */
730 /* or it may contain some interiors, then change */
731 /* the contained interiors to exterior ones */
732 add_interior_with_hierarchy_check(tobj
, outer
, contour
);
735 /* not in interior, add as new interior contour */
736 add_new_interior(tobj
, outer
, contour
);
746 /* add contour to the exterior sequence */
747 add_new_exterior(tobj
, contour
);
751 tess_handle_holes(GLUtriangulatorObj
* tobj
)
753 tess_contour
*contour
, *hole
;
754 GLenum exterior_orientation
;
756 /* verify hole orientation */
757 for (contour
= tobj
->contours
; contour
!= NULL
;) {
758 exterior_orientation
= contour
->orientation
;
759 for (contour
= contour
->next
;
760 contour
!= NULL
&& contour
->type
== GLU_INTERIOR
;
761 contour
= contour
->next
) {
762 if (contour
->orientation
== exterior_orientation
) {
763 tess_call_user_error(tobj
, GLU_TESS_ERROR5
);
768 /* now cut-out holes */
769 for (contour
= tobj
->contours
; contour
!= NULL
;) {
770 hole
= contour
->next
;
771 while (hole
!= NULL
&& hole
->type
== GLU_INTERIOR
) {
772 if (cut_out_hole(tobj
, contour
, hole
) == GLU_ERROR
)
774 hole
= contour
->next
;
776 contour
= contour
->next
;
781 cut_out_hole(GLUtriangulatorObj
* tobj
,
782 tess_contour
* contour
, tess_contour
* hole
)
784 tess_contour
*tmp_hole
;
785 tess_vertex
*v1
, *v2
, *tmp_vertex
;
786 GLuint vertex1_cnt
, vertex2_cnt
, tmp_vertex_cnt
;
790 /* find an edge connecting contour and hole not intersecting any other */
791 /* edge belonging to either the contour or any of the other holes */
792 for (v1
= contour
->vertices
, vertex1_cnt
= contour
->vertex_cnt
, i
= 0;
793 i
< vertex1_cnt
; i
++, v1
= v1
->next
) {
794 for (v2
= hole
->vertices
, vertex2_cnt
= hole
->vertex_cnt
, j
= 0;
795 j
< vertex2_cnt
; j
++, v2
= v2
->next
) {
796 /* does edge (v1,v2) intersect any edge of contour */
797 for (tmp_vertex
= contour
->vertices
, tmp_vertex_cnt
=
798 contour
->vertex_cnt
, k
= 0; k
< tmp_vertex_cnt
;
799 tmp_vertex
= tmp_vertex
->next
, k
++) {
800 /* skip edge tests for edges directly connected */
801 if (v1
== tmp_vertex
|| v1
== tmp_vertex
->next
)
803 test
= edge_edge_intersect(v1
, v2
, tmp_vertex
, tmp_vertex
->next
);
804 if (test
!= GLU_NO_ERROR
)
807 if (test
== GLU_NO_ERROR
) {
808 /* does edge (v1,v2) intersect any edge of hole */
809 for (tmp_vertex
= hole
->vertices
,
810 tmp_vertex_cnt
= hole
->vertex_cnt
, k
= 0;
811 k
< tmp_vertex_cnt
; tmp_vertex
= tmp_vertex
->next
, k
++) {
812 /* skip edge tests for edges directly connected */
813 if (v2
== tmp_vertex
|| v2
== tmp_vertex
->next
)
816 edge_edge_intersect(v1
, v2
, tmp_vertex
, tmp_vertex
->next
);
817 if (test
!= GLU_NO_ERROR
)
820 if (test
== GLU_NO_ERROR
) {
821 /* does edge (v1,v2) intersect any other hole? */
822 for (tmp_hole
= hole
->next
;
823 tmp_hole
!= NULL
&& tmp_hole
->type
== GLU_INTERIOR
;
824 tmp_hole
= tmp_hole
->next
) {
825 /* does edge (v1,v2) intersect any edge of hole */
826 for (tmp_vertex
= tmp_hole
->vertices
,
827 tmp_vertex_cnt
= tmp_hole
->vertex_cnt
, k
= 0;
828 k
< tmp_vertex_cnt
; tmp_vertex
= tmp_vertex
->next
, k
++) {
829 test
= edge_edge_intersect(v1
, v2
, tmp_vertex
,
831 if (test
!= GLU_NO_ERROR
)
834 if (test
!= GLU_NO_ERROR
)
839 if (test
== GLU_NO_ERROR
) {
840 /* edge (v1,v2) is good for eliminating the hole */
841 if (merge_hole_with_contour(tobj
, contour
, hole
, v1
, v2
)
849 /* other holes are blocking all possible connections of hole */
850 /* with contour, we shift this hole as the last hole and retry */
851 for (tmp_hole
= hole
;
852 tmp_hole
!= NULL
&& tmp_hole
->type
== GLU_INTERIOR
;
853 tmp_hole
= tmp_hole
->next
);
854 contour
->next
= hole
->next
;
855 hole
->next
->previous
= contour
;
856 if (tmp_hole
== NULL
) {
857 /* last EXTERIOR contour, shift hole as last contour */
859 hole
->previous
= tobj
->last_contour
;
860 tobj
->last_contour
->next
= hole
;
861 tobj
->last_contour
= hole
;
864 tmp_hole
->previous
->next
= hole
;
865 hole
->previous
= tmp_hole
->previous
;
866 tmp_hole
->previous
= hole
;
867 hole
->next
= tmp_hole
;
869 hole
= contour
->next
;
870 /* try once again - recurse */
871 return cut_out_hole(tobj
, contour
, hole
);
875 merge_hole_with_contour(GLUtriangulatorObj
* tobj
,
876 tess_contour
* contour
,
878 tess_vertex
* v1
, tess_vertex
* v2
)
880 tess_vertex
*v1_new
, *v2_new
;
882 /* make copies of v1 and v2, place them respectively after their originals */
883 if ((v1_new
= (tess_vertex
*) malloc(sizeof(tess_vertex
))) == NULL
) {
884 tess_call_user_error(tobj
, GLU_OUT_OF_MEMORY
);
887 if ((v2_new
= (tess_vertex
*) malloc(sizeof(tess_vertex
))) == NULL
) {
888 tess_call_user_error(tobj
, GLU_OUT_OF_MEMORY
);
891 v1_new
->edge_flag
= GL_TRUE
;
892 v1_new
->data
= v1
->data
;
893 v1_new
->location
[0] = v1
->location
[0];
894 v1_new
->location
[1] = v1
->location
[1];
895 v1_new
->location
[2] = v1
->location
[2];
898 v1_new
->shadow_vertex
= v1
;
899 v1
->shadow_vertex
= v1_new
;
900 v1_new
->next
= v1
->next
;
901 v1_new
->previous
= v1
;
902 v1
->next
->previous
= v1_new
;
904 v2_new
->edge_flag
= GL_TRUE
;
905 v2_new
->data
= v2
->data
;
906 v2_new
->location
[0] = v2
->location
[0];
907 v2_new
->location
[1] = v2
->location
[1];
908 v2_new
->location
[2] = v2
->location
[2];
911 v2_new
->shadow_vertex
= v2
;
912 v2
->shadow_vertex
= v2_new
;
913 v2_new
->next
= v2
->next
;
914 v2_new
->previous
= v2
;
915 v2
->next
->previous
= v2_new
;
917 /* link together the two lists */
919 v2_new
->previous
= v1
;
921 v1_new
->previous
= v2
;
922 /* update the vertex count of the contour */
923 contour
->vertex_cnt
+= hole
->vertex_cnt
+ 2;
924 /* remove the INTERIOR contour */
925 contour
->next
= hole
->next
;
926 if (hole
->next
!= NULL
)
927 hole
->next
->previous
= contour
;
929 /* update tobj structure */
930 --(tobj
->contour_cnt
);
931 if (contour
->last_vertex
== v1
)
932 contour
->last_vertex
= v1_new
;
933 /* mark two vertices with edge_flag */
934 v2
->edge_flag
= GL_FALSE
;
935 v1
->edge_flag
= GL_FALSE
;