2 Generic Polygon Clipper
4 A new algorithm for calculating the difference, intersection,
5 exclusive-or or union of arbitrary polygon sets.
7 Written by Alan Murta (email: gpc@cs.man.ac.uk)
9 [http://www.cs.man.ac.uk/~toby/alan/software/|Original GPC site].
11 Current version is 2.33 (21st May 2014).
13 Ported to D by Ketmar // Invisible Vector.
15 GPC is using standard libc `malloc()`, `realloc()` and `free()` functions
18 Copyright (C) Advanced Interfaces Group, University of Manchester.
20 This software is free for non-commercial use. It may be copied,
21 modified, and redistributed provided that this copyright notice
22 is preserved on all copies. The intellectual property rights of
23 the algorithms used reside with the University of Manchester
24 Advanced Interfaces Group.
26 You may not use this software, in whole or in part, in support
27 of any commercial product without the express consent of the
30 There is no warranty or other guarantee of fitness of this
31 software for any purpose. It is provided solely "as is".
34 private nothrow @trusted @nogc:
37 ===========================================================================
39 ===========================================================================
42 private enum DBL_EPSILON
= double.epsilon
; //cast(double)2.2204460492503131e-16;
44 version(gpc_use_custom_epsilon
) {
45 public double GPC_EPSILON
= DBL_EPSILON
; /// Increase GPC_EPSILON to encourage merging of near coincident edges
47 public enum GPC_EPSILON
= DBL_EPSILON
; /// Increase GPC_EPSILON to encourage merging of near coincident edges
50 public bool GPC_INVERT_TRISTRIPS
= false;
52 version(gpc_use_custom_epsilon
) {
53 /// Compares two floating point numbers using [GPC_EPSILON] as epsilon value.
54 public bool gpc_eq (in double a
, in double b
) nothrow @safe @nogc { pragma(inline
, true); import std
.math
; return (abs(a
-b
) <= GPC_EPSILON
); }
56 /// Compares two floating point numbers using [GPC_EPSILON] as epsilon value.
57 public bool gpc_eq (in double a
, in double b
) pure nothrow @safe @nogc { pragma(inline
, true); import std
.math
; return (abs(a
-b
) <= GPC_EPSILON
); }
62 ===========================================================================
64 ===========================================================================
67 /// Set operation type
75 /// Polygon vertex structure
76 public struct gpc_vertex
{
77 double x
; /// vertex x component
78 double y
; /// vertex y component
81 /// Vertex list structure
82 public struct gpc_vertex_list
{
83 int num_vertices
; /// Number of vertices in list
84 gpc_vertex
* vertex
; /// Vertex array pointer
87 /// Polygon set structure
88 public struct gpc_polygon
{
89 int num_contours
; /// Number of contours in polygon
90 int* hole
; /// Hole / external contour flags
91 gpc_vertex_list
* contour
; /// Contour array pointer
94 /// Tristrip set structure
95 public struct gpc_tristrip
{
96 int num_strips
; /// Number of tristrips
97 gpc_vertex_list
* strip
; /// Tristrip array pointer
103 ===========================================================================
105 ===========================================================================
119 ===========================================================================
121 ===========================================================================
124 version(gpc_use_custom_epsilon
) {
125 bool EQ(T
) (in T a
, in T b
) nothrow @safe @nogc { pragma(inline
, true); import std
.math
; return (abs(a
-b
) <= GPC_EPSILON
); }
127 bool EQ(T
) (in T a
, in T b
) pure nothrow @safe @nogc { pragma(inline
, true); import std
.math
; return (abs(a
-b
) <= GPC_EPSILON
); }
130 T
PREV_INDEX(T
) (in T i
, in T n
) pure nothrow @safe @nogc { pragma(inline
, true); return (i
-1+n
)%n
; }
131 T
NEXT_INDEX(T
) (in T i
, in T n
) pure nothrow @safe @nogc { pragma(inline
, true); return (i
+1)%n
; }
133 bool OPTIMAL(TV
, T
) (const(TV
)* v
, in T i
, in T n
) pure nothrow @trusted @nogc { pragma(inline
, true); return ((v
[PREV_INDEX(i
, n
)].y
!= v
[i
].y
) ||
(v
[NEXT_INDEX(i
, n
)].y
!= v
[i
].y
)); }
135 bool FWD_MIN(TV
, T
) (const(TV
)* v
, in T i
, in T n
) pure nothrow @trusted @nogc { pragma(inline
, true); return ((v
[PREV_INDEX(i
, n
)].vertex
.y
>= v
[i
].vertex
.y
) && (v
[NEXT_INDEX(i
, n
)].vertex
.y
> v
[i
].vertex
.y
)); }
137 bool NOT_FMAX(TV
, T
) (const(TV
)* v
, in T i
, in T n
) pure nothrow @trusted @nogc { pragma(inline
, true); return (v
[NEXT_INDEX(i
, n
)].vertex
.y
> v
[i
].vertex
.y
); }
139 bool REV_MIN(TV
, T
) (const(TV
)* v
, in T i
, in T n
) pure nothrow @trusted @nogc { pragma(inline
, true); return ((v
[PREV_INDEX(i
, n
)].vertex
.y
> v
[i
].vertex
.y
) && (v
[NEXT_INDEX(i
, n
)].vertex
.y
>= v
[i
].vertex
.y
)); }
141 bool NOT_RMAX(TV
, T
) (const(TV
)* v
, in T i
, in T n
) pure nothrow @trusted @nogc { pragma(inline
, true); return (v
[PREV_INDEX(i
, n
)].vertex
.y
> v
[i
].vertex
.y
); }
143 void VERTEX(T
) (ref edge_node
* e
, in int p
, in int s
, in T x
, in T y
) nothrow @trusted @nogc { pragma(inline
, true); add_vertex(&((e
).outp
[(p
)].v
[(s
)]), x
, y
); (e
).outp
[(p
)].active
++; }
145 void P_EDGE(T
) (ref edge_node
* d
, ref edge_node
* e
, in int p
, ref T i
, in T j
) nothrow @trusted @nogc {
147 do { (d
)= (d
).prev
; } while (!(d
).outp
[(p
)]);
148 (i
)= (d
).bot
.x
+ (d
).dx
* ((j
)-(d
).bot
.y
);
151 void N_EDGE(T
) (ref edge_node
* d
, ref edge_node
* e
, in int p
, ref T i
, in T j
) nothrow @trusted @nogc {
153 do { (d
)= (d
).next
; } while (!(d
).outp
[(p
)]);
154 (i
) = (d
).bot
.x
+ (d
).dx
* ((j
)-(d
).bot
.y
);
158 T
* MALLOC(T
) (uint count
=1) nothrow @trusted @nogc {
159 import core
.stdc
.stdlib
: malloc
;
160 static assert(T
.sizeof
> 0);
161 if (count
== 0) return null;
162 if (count
>= int.max
/4/T
.sizeof
) assert(0, "gpc malloc failure");
163 T
* p
= cast(T
*)malloc(T
.sizeof
*count
);
164 if (p
is null) assert(0, "gpc malloc failure");
168 void REALLOC(T
) (ref T
* p
, uint count
) nothrow @trusted @nogc {
169 import core
.stdc
.stdlib
: free
, realloc
;
171 if (count
!= 0) p
= MALLOC
!T(count
);
172 } else if (count
== 0) {
178 static assert(T
.sizeof
> 0);
180 if (count
>= int.max
/4/T
.sizeof
) assert(0, "gpc malloc failure");
181 T
* np
= cast(T
*)realloc(p
, T
.sizeof
*count
);
182 if (np
is null) assert(0, "gpc malloc failure");
187 void FREE(T
) (ref T
* ptr
) nothrow @trusted @nogc {
188 import core
.stdc
.stdlib
: free
;
189 if (ptr
!is null) { free(ptr
); ptr
= null; }
194 ===========================================================================
196 ===========================================================================
199 // Edge intersection classes
200 alias vertex_type
= int;
202 NUL
, // Empty non-intersection
203 EMX
, // External maximum
204 ELI
, // External left intermediate
206 ERI
, // External right intermediate
208 IMM
, // Internal maximum and minimum
209 IMN
, // Internal minimum
210 EMN
, // External minimum
211 EMM
, // External maximum and minimum
213 ILI
, // Internal left intermediate
215 IRI
, // Internal right intermediate
216 IMX
, // Internal maximum
217 FUL
, // Full non-intersection
220 // Horizontal edge states
223 NH
, // No horizontal edge
224 BH
, // Bottom horizontal edge
225 TH
, // Top horizontal edge
229 alias bundle_state
= int;
231 UNBUNDLED
, // Isolated edge not within a bundle
232 BUNDLE_HEAD
, // Bundle head node
233 BUNDLE_TAIL
, // Passive bundle tail node
236 // Internal vertex list datatype
237 //alias v_shape = vertex_node;
239 double x
; // X coordinate component
240 double y
; // Y coordinate component
241 vertex_node
* next
; // Pointer to next vertex in list
245 // Internal contour / tristrip type
246 struct polygon_node
{
247 int active
; // Active flag / vertex count
248 int hole
; // Hole / external contour flag
249 vertex_node
*[2] v
; // Left and right vertex list ptrs
250 polygon_node
* next
; // Pointer to next polygon contour
251 polygon_node
* proxy
; // Pointer to actual structure used
256 gpc_vertex vertex
; // Piggy-backed contour vertex data
257 gpc_vertex bot
; // Edge lower (x, y) coordinate
258 gpc_vertex top
; // Edge upper (x, y) coordinate
259 double xb
; // Scanbeam bottom x coordinate
260 double xt
; // Scanbeam top x coordinate
261 double dx
; // Change in x for a unit y increase
262 int type
; // Clip / subject edge flag
263 int[2][2] bundle
; // Bundle edge flags
264 int[2] bside
; // Bundle left / right indicators
265 bundle_state
[2] bstate
; // Edge bundle state
266 polygon_node
*[2] outp
; // Output polygon / tristrip pointer
267 edge_node
* prev
; // Previous edge in the AET
268 edge_node
* next
; // Next edge in the AET
269 edge_node
* pred
; // Edge connected at the lower end
270 edge_node
* succ
; // Edge connected at the upper end
271 edge_node
* next_bound
; // Pointer to next bound in LMT
275 // Local minima table
277 double y
; // Y coordinate at local minimum
278 edge_node
* first_bound
; // Pointer to bound list
279 lmt_node
* next
; // Pointer to next local minimum
285 double y
; // Scanbeam node y value
286 sb_tree
* less
; // Pointer to nodes with lower y
287 sb_tree
* more
; // Pointer to nodes with higher y
291 // Intersection table
293 edge_node
*[2] ie
; // Intersecting edge (bundle) pair
294 gpc_vertex point
; // Point of intersection
295 it_node
* next
; // The next intersection table node
301 edge_node
* edge
; // Pointer to AET edge
302 double xb
; // Scanbeam bottom x coordinate
303 double xt
; // Scanbeam top x coordinate
304 double dx
; // Change in x for a unit y increase
305 st_node
* prev
; // Previous edge in sorted list
309 // Contour axis-aligned bounding box
311 double xmin
; // Minimum x coordinate
312 double ymin
; // Minimum y coordinate
313 double xmax
; // Maximum x coordinate
314 double ymax
; // Maximum y coordinate
319 ===========================================================================
321 ===========================================================================
324 // Horizontal edge state transitions within scanbeam boundary
325 static immutable h_state
[6][3] next_h_state
= [
326 /* ABOVE BELOW CROSS */
328 /* NH */ [BH
, TH
, TH
, BH
, NH
, NH
],
329 /* BH */ [NH
, NH
, NH
, NH
, TH
, TH
],
330 /* TH */ [NH
, NH
, NH
, NH
, BH
, BH
],
335 ===========================================================================
337 ===========================================================================
340 private void reset_it (it_node
** it
) {
342 it_node
* itn
= (*it
).next
;
349 private void reset_lmt (lmt_node
** lmt
) {
351 lmt_node
* lmtn
= (*lmt
).next
;
358 private void insert_bound (edge_node
** b
, edge_node
* e
) {
359 edge_node
* existing_bound
;
362 // Link node e to the tail of the list
365 // Do primary sort on the x field
366 if (e
[0].bot
.x
< (*b
)[0].bot
.x
) {
367 // Insert a new node mid-list
370 (*b
).next_bound
= existing_bound
;
372 if (e
[0].bot
.x
== (*b
)[0].bot
.x
) {
373 // Do secondary sort on the dx field
374 if (e
[0].dx
< (*b
)[0].dx
) {
375 // Insert a new node mid-list
378 (*b
).next_bound
= existing_bound
;
380 // Head further down the list
381 insert_bound(&((*b
).next_bound
), e
);
384 // Head further down the list
385 insert_bound(&((*b
).next_bound
), e
);
392 private edge_node
** bound_list (lmt_node
** lmt
, double y
) {
393 lmt_node
* existing_node
;
396 // Add node onto the tail end of the LMT
397 *lmt
= MALLOC
!lmt_node();
399 (*lmt
).first_bound
= null;
401 return &((*lmt
).first_bound
);
402 } else if (y
< (*lmt
).y
) {
403 // Insert a new LMT node before the current node
404 existing_node
= *lmt
;
405 *lmt
= MALLOC
!lmt_node();
407 (*lmt
).first_bound
= null;
408 (*lmt
).next
= existing_node
;
409 return &((*lmt
).first_bound
);
410 } else if (y
> (*lmt
).y
) {
411 // Head further up the LMT
412 return bound_list(&((*lmt
).next
), y
);
414 // Use this existing LMT node
415 return &((*lmt
).first_bound
);
420 private void add_to_sbtree (int* entries
, sb_tree
** sbtree
, double y
) {
422 // Add a new tree node here
423 *sbtree
= MALLOC
!sb_tree();
425 (*sbtree
).less
= null;
426 (*sbtree
).more
= null;
429 if ((*sbtree
).y
> y
) {
430 // Head into the 'less' sub-tree
431 add_to_sbtree(entries
, &((*sbtree
).less
), y
);
433 if ((*sbtree
).y
< y
) {
434 // Head into the 'more' sub-tree
435 add_to_sbtree(entries
, &((*sbtree
).more
), y
);
442 private void build_sbt (int* entries
, double* sbt
, sb_tree
* sbtree
) {
443 if (sbtree
.less
) build_sbt(entries
, sbt
, sbtree
.less
);
444 sbt
[*entries
]= sbtree
.y
;
446 if (sbtree
.more
) build_sbt(entries
, sbt
, sbtree
.more
);
450 private void free_sbtree (sb_tree
** sbtree
) {
452 free_sbtree(&((*sbtree
).less
));
453 free_sbtree(&((*sbtree
).more
));
459 private int count_optimal_vertices (gpc_vertex_list c
) {
461 // Ignore non-contributing contours
462 if (c
.num_vertices
> 0) {
463 foreach (immutable int i
; 0..c
.num_vertices
) {
464 // Ignore superfluous vertices embedded in horizontal edges
465 if (OPTIMAL(c
.vertex
, i
, c
.num_vertices
)) ++result
;
472 private edge_node
* build_lmt (lmt_node
** lmt
, sb_tree
** sbtree
, int* sbt_entries
, gpc_polygon
* p
, int type
, GPC op
) {
473 int min
, max
, num_edges
, v
, num_vertices
;
474 int total_vertices
= 0, e_index
= 0;
475 edge_node
* e
, edge_table
;
477 foreach (immutable int c
; 0..p
.num_contours
) total_vertices
+= count_optimal_vertices(p
.contour
[c
]);
479 // Create the entire input polygon edge table in one go
480 edge_table
= MALLOC
!edge_node(total_vertices
);
482 foreach (immutable int c
; 0..p
.num_contours
) {
483 if (p
.contour
[c
].num_vertices
< 0) {
484 // Ignore the non-contributing contour and repair the vertex count
485 p
.contour
[c
].num_vertices
= -p
.contour
[c
].num_vertices
;
487 // Perform contour optimisation
489 foreach (immutable int i
; 0..p
.contour
[c
].num_vertices
) {
490 if (OPTIMAL(p
.contour
[c
].vertex
, i
, p
.contour
[c
].num_vertices
)) {
491 edge_table
[num_vertices
].vertex
.x
= p
.contour
[c
].vertex
[i
].x
;
492 edge_table
[num_vertices
].vertex
.y
= p
.contour
[c
].vertex
[i
].y
;
493 // Record vertex in the scanbeam table
494 add_to_sbtree(sbt_entries
, sbtree
, edge_table
[num_vertices
].vertex
.y
);
499 // Do the contour forward pass
500 for (min
= 0; min
< num_vertices
; ++min
) {
501 // If a forward local minimum...
502 if (FWD_MIN(edge_table
, min
, num_vertices
)) {
503 // Search for the next local maximum...
505 max
= NEXT_INDEX(min
, num_vertices
);
506 while (NOT_FMAX(edge_table
, max
, num_vertices
)) {
508 max
= NEXT_INDEX(max
, num_vertices
);
511 // Build the next edge list
512 e
= &edge_table
[e_index
];
513 e_index
+= num_edges
;
515 e
[0].bstate
[BELOW
] = UNBUNDLED
;
516 e
[0].bundle
[BELOW
][CLIP
] = false;
517 e
[0].bundle
[BELOW
][SUBJ
] = false;
518 foreach (immutable int i
; 0..num_edges
) {
519 e
[i
].xb
= edge_table
[v
].vertex
.x
;
520 e
[i
].bot
.x
= edge_table
[v
].vertex
.x
;
521 e
[i
].bot
.y
= edge_table
[v
].vertex
.y
;
523 v
= NEXT_INDEX(v
, num_vertices
);
525 e
[i
].top
.x
= edge_table
[v
].vertex
.x
;
526 e
[i
].top
.y
= edge_table
[v
].vertex
.y
;
527 e
[i
].dx
= (edge_table
[v
].vertex
.x
- e
[i
].bot
.x
) / (e
[i
].top
.y
- e
[i
].bot
.y
);
529 e
[i
].outp
[ABOVE
] = null;
530 e
[i
].outp
[BELOW
] = null;
533 e
[i
].succ
= ((num_edges
> 1) && (i
< (num_edges
- 1))) ?
&(e
[i
+ 1]) : null;
534 e
[i
].pred
= ((num_edges
> 1) && (i
> 0)) ?
&(e
[i
- 1]) : null;
535 e
[i
].next_bound
= null;
536 e
[i
].bside
[CLIP
] = (op
== GPC
.Diff ? RIGHT
: LEFT
);
537 e
[i
].bside
[SUBJ
] = LEFT
;
539 insert_bound(bound_list(lmt
, edge_table
[min
].vertex
.y
), e
);
543 // Do the contour reverse pass
544 for (min
= 0; min
< num_vertices
; ++min
) {
545 // If a reverse local minimum...
546 if (REV_MIN(edge_table
, min
, num_vertices
)) {
547 // Search for the previous local maximum...
549 max
= PREV_INDEX(min
, num_vertices
);
550 while (NOT_RMAX(edge_table
, max
, num_vertices
)) {
552 max
= PREV_INDEX(max
, num_vertices
);
555 // Build the previous edge list
556 e
= &edge_table
[e_index
];
557 e_index
+= num_edges
;
559 e
[0].bstate
[BELOW
] = UNBUNDLED
;
560 e
[0].bundle
[BELOW
][CLIP
] = false;
561 e
[0].bundle
[BELOW
][SUBJ
] = false;
562 foreach (immutable i
; 0..num_edges
) {
563 e
[i
].xb
= edge_table
[v
].vertex
.x
;
564 e
[i
].bot
.x
= edge_table
[v
].vertex
.x
;
565 e
[i
].bot
.y
= edge_table
[v
].vertex
.y
;
567 v
= PREV_INDEX(v
, num_vertices
);
569 e
[i
].top
.x
= edge_table
[v
].vertex
.x
;
570 e
[i
].top
.y
= edge_table
[v
].vertex
.y
;
571 e
[i
].dx
= (edge_table
[v
].vertex
.x
- e
[i
].bot
.x
) / (e
[i
].top
.y
- e
[i
].bot
.y
);
573 e
[i
].outp
[ABOVE
] = null;
574 e
[i
].outp
[BELOW
] = null;
577 e
[i
].succ
= ((num_edges
> 1) && (i
< (num_edges
- 1))) ?
&(e
[i
+ 1]) : null;
578 e
[i
].pred
= ((num_edges
> 1) && (i
> 0)) ?
&(e
[i
- 1]) : null;
579 e
[i
].next_bound
= null;
580 e
[i
].bside
[CLIP
] = (op
== GPC
.Diff ? RIGHT
: LEFT
);
581 e
[i
].bside
[SUBJ
] = LEFT
;
583 insert_bound(bound_list(lmt
, edge_table
[min
].vertex
.y
), e
);
592 private void add_edge_to_aet (edge_node
** aet
, edge_node
* edge
, edge_node
* prev
) {
594 // Append edge onto the tail end of the AET
599 // Do primary sort on the xb field
600 if (edge
.xb
< (*aet
).xb
) {
601 // Insert edge here (before the AET edge)
607 if (edge
.xb
== (*aet
).xb
) {
608 // Do secondary sort on the dx field
609 if (edge
.dx
< (*aet
).dx
) {
610 // Insert edge here (before the AET edge)
616 // Head further into the AET
617 add_edge_to_aet(&((*aet
).next
), edge
, *aet
);
620 // Head further into the AET
621 add_edge_to_aet(&((*aet
).next
), edge
, *aet
);
628 private void add_intersection (it_node
** it
, edge_node
* edge0
, edge_node
* edge1
, double x
, double y
) {
629 it_node
* existing_node
;
632 // Append a new node to the tail of the list
633 *it
= MALLOC
!it_node();
640 if ((*it
).point
.y
> y
) {
641 // Insert a new node mid-list
643 *it
= MALLOC
!it_node();
648 (*it
).next
= existing_node
;
650 // Head further down the list
651 add_intersection(&((*it
).next
), edge0
, edge1
, x
, y
);
657 private void add_st_edge (st_node
** st
, it_node
** it
, edge_node
* edge
, double dy
) {
658 import std
.math
: abs
;
660 st_node
* existing_node
;
664 // Append edge onto the tail end of the ST
665 *st
= MALLOC
!st_node();
672 den
= ((*st
).xt
- (*st
).xb
) - (edge
.xt
- edge
.xb
);
674 // If new edge and ST edge don't cross
675 if (edge
.xt
>= (*st
).xt || edge
.dx
== (*st
).dx ||
abs(den
) <= DBL_EPSILON
) {
676 // No intersection - insert edge here (before the ST edge)
678 *st
= MALLOC
!st_node();
683 (*st
).prev
= existing_node
;
685 // Compute intersection between new edge and ST edge
686 r
= (edge
.xb
- (*st
).xb
) / den
;
687 x
= (*st
).xb
+ r
* ((*st
).xt
- (*st
).xb
);
690 // Insert the edge pointers and the intersection point in the IT
691 add_intersection(it
, (*st
).edge
, edge
, x
, y
);
693 // Head further into the ST
694 add_st_edge(&((*st
).prev
), it
, edge
, dy
);
700 private void build_intersection_table (it_node
** it
, edge_node
* aet
, double dy
) {
704 // Build intersection table for the current scanbeam
708 // Process each AET edge
709 for (edge
= aet
; edge
!is null; edge
= edge
.next
) {
710 if (edge
.bstate
[ABOVE
] == BUNDLE_HEAD || edge
.bundle
[ABOVE
][CLIP
] || edge
.bundle
[ABOVE
][SUBJ
]) {
711 add_st_edge(&st
, it
, edge
, dy
);
715 // Free the sorted edge table
716 while (st
!is null) {
724 private void swap_intersecting_edge_bundles (edge_node
** aet
, it_node
* intersect
) {
725 edge_node
* e0
= intersect
.ie
[0];
726 edge_node
* e1
= intersect
.ie
[1];
729 edge_node
* e0n
= e0
.next
;
730 edge_node
* e1n
= e1
.next
;
732 // Find the node before the e0 bundle
733 edge_node
* e0p
= e0
.prev
;
734 if (e0
.bstate
[ABOVE
] == BUNDLE_HEAD
) {
738 } while (e0p
&& (e0p
.bstate
[ABOVE
] == BUNDLE_TAIL
));
741 // Find the node before the e1 bundle
742 edge_node
* e1p
= e1
.prev
;
743 if (e1
.bstate
[ABOVE
] == BUNDLE_HEAD
) {
747 } while (e1p
&& (e1p
.bstate
[ABOVE
] == BUNDLE_TAIL
));
750 // Swap the e0p and e1p links
781 if (e1n
) e1n
.prev
= e0
;
790 if (e0n
) e0n
.prev
= e1
;
798 private int count_contours (polygon_node
* polygon
) {
800 vertex_node
* v
, nextv
;
802 for (nc
= 0; polygon
!is null; polygon
= polygon
.next
) {
803 if (polygon
.active
) {
804 // Count the vertices in the current contour
806 for (v
= polygon
.proxy
.v
[LEFT
]; v
; v
= v
.next
) ++nv
;
808 // Record valid vertex counts in the active field
813 // Invalid contour: just free the heap
814 for (v
= polygon
.proxy
.v
[LEFT
]; v
!is null; v
= nextv
) {
827 private void add_left (polygon_node
* p
, double x
, double y
) {
830 // Create a new vertex node and set its fields
831 nv
= MALLOC
!vertex_node();
835 // Add vertex nv to the left end of the polygon's vertex list
836 nv
.next
= p
.proxy
.v
[LEFT
];
838 // Update proxy.[LEFT] to point to nv
839 p
.proxy
.v
[LEFT
] = nv
;
843 private void merge_left (polygon_node
* p
, polygon_node
* q
, polygon_node
* list
) {
844 polygon_node
* target
;
846 // Label contour as a hole
849 if (p
.proxy
!is q
.proxy
) {
850 // Assign p's vertex list to the left end of q's list
851 p
.proxy
.v
[RIGHT
].next
= q
.proxy
.v
[LEFT
];
852 q
.proxy
.v
[LEFT
] = p
.proxy
.v
[LEFT
];
854 // Redirect any p.proxy references to q.proxy
855 for (target
= p
.proxy
; list
!is null; list
= list
.next
) {
856 if (list
.proxy
is target
) {
858 list
.proxy
= q
.proxy
;
865 private void add_right (polygon_node
* p
, double x
, double y
) {
868 // Create a new vertex node and set its fields
869 nv
= MALLOC
!vertex_node();
874 // Add vertex nv to the right end of the polygon's vertex list
875 p
.proxy
.v
[RIGHT
].next
= nv
;
877 // Update proxy.v[RIGHT] to point to nv
878 p
.proxy
.v
[RIGHT
] = nv
;
882 private void merge_right (polygon_node
* p
, polygon_node
* q
, polygon_node
* list
) {
883 polygon_node
* target
;
885 // Label contour as external
886 q
.proxy
.hole
= false;
888 if (p
.proxy
!is q
.proxy
) {
889 // Assign p's vertex list to the right end of q's list
890 q
.proxy
.v
[RIGHT
].next
= p
.proxy
.v
[LEFT
];
891 q
.proxy
.v
[RIGHT
] = p
.proxy
.v
[RIGHT
];
893 // Redirect any p.proxy references to q.proxy
894 for (target
= p
.proxy
; list
!is null; list
= list
.next
) {
895 if (list
.proxy
is target
) {
897 list
.proxy
= q
.proxy
;
904 private void add_local_min (polygon_node
** p
, edge_node
* edge
, double x
, double y
) {
905 polygon_node
* existing_min
;
910 *p
= MALLOC
!polygon_node();
912 // Create a new vertex node and set its fields
913 nv
= MALLOC
!vertex_node();
918 // Initialise proxy to point to p itself
921 (*p
).next
= existing_min
;
923 // Make v[LEFT] and v[RIGHT] point to new vertex nv
927 // Assign polygon p to the edge
928 edge
.outp
[ABOVE
] = *p
;
932 private int count_tristrips (polygon_node
* tn
) {
934 for (total
= 0; tn
!is null; tn
= tn
.next
) if (tn
.active
> 2) ++total
;
939 private void add_vertex (vertex_node
** t
, double x
, double y
) {
941 *t
= MALLOC
!vertex_node();
946 // Head further down the list
947 add_vertex(&((*t
).next
), x
, y
);
952 private void new_tristrip (polygon_node
** tn
, edge_node
* edge
, double x
, double y
) {
954 *tn
= MALLOC
!polygon_node();
956 (*tn
).v
[LEFT
] = null;
957 (*tn
).v
[RIGHT
] = null;
959 add_vertex(&((*tn
).v
[LEFT
]), x
, y
);
960 edge
.outp
[ABOVE
] = *tn
;
962 // Head further down the list
963 new_tristrip(&((*tn
).next
), edge
, x
, y
);
968 private bbox
* create_contour_bboxes (gpc_polygon
* p
) {
969 bbox
* box
= MALLOC
!bbox(p
.num_contours
);
971 // Construct contour bounding boxes
972 foreach (immutable int c
; 0..p
.num_contours
) {
973 // Initialise bounding box extent
974 box
[c
].xmin
= double.max
;
975 box
[c
].ymin
= double.max
;
976 box
[c
].xmax
= -double.max
;
977 box
[c
].ymax
= -double.max
;
979 foreach (immutable int v
; 0..p
.contour
[c
].num_vertices
) {
980 // Adjust bounding box
981 if (p
.contour
[c
].vertex
[v
].x
< box
[c
].xmin
) box
[c
].xmin
= p
.contour
[c
].vertex
[v
].x
;
982 if (p
.contour
[c
].vertex
[v
].y
< box
[c
].ymin
) box
[c
].ymin
= p
.contour
[c
].vertex
[v
].y
;
983 if (p
.contour
[c
].vertex
[v
].x
> box
[c
].xmax
) box
[c
].xmax
= p
.contour
[c
].vertex
[v
].x
;
984 if (p
.contour
[c
].vertex
[v
].y
> box
[c
].ymax
) box
[c
].ymax
= p
.contour
[c
].vertex
[v
].y
;
992 private void minimax_test (gpc_polygon
* subj
, gpc_polygon
* clip
, GPC op
) {
993 bbox
* s_bbox
, c_bbox
;
997 s_bbox
= create_contour_bboxes(subj
);
998 c_bbox
= create_contour_bboxes(clip
);
1000 o_table
= MALLOC
!int(subj
.num_contours
*clip
.num_contours
);
1002 // Check all subject contour bounding boxes against clip boxes
1003 foreach (immutable int s
; 0..subj
.num_contours
) {
1004 foreach (immutable int c
; 0..clip
.num_contours
) {
1005 o_table
[c
*subj
.num_contours
+ s
] =
1006 (!((s_bbox
[s
].xmax
< c_bbox
[c
].xmin
) ||
1007 (s_bbox
[s
].xmin
> c_bbox
[c
].xmax
))) &&
1008 (!((s_bbox
[s
].ymax
< c_bbox
[c
].ymin
) ||
1009 (s_bbox
[s
].ymin
> c_bbox
[c
].ymax
)));
1013 // For each clip contour, search for any subject contour overlaps
1014 foreach (immutable int c
; 0..clip
.num_contours
) {
1016 for (int s
= 0; !overlap
&& s
< subj
.num_contours
; ++s
) overlap
= o_table
[c
* subj
.num_contours
+ s
];
1017 // Flag non contributing status by negating vertex count
1018 if (!overlap
) clip
.contour
[c
].num_vertices
= -clip
.contour
[c
].num_vertices
;
1021 if (op
== GPC
.Int
) {
1022 // For each subject contour, search for any clip contour overlaps
1023 foreach (immutable int s
; 0..subj
.num_contours
) {
1025 for (int c
= 0; !overlap
&& c
< clip
.num_contours
; ++c
) overlap
= o_table
[c
* subj
.num_contours
+ s
];
1026 // Flag non contributing status by negating vertex count
1027 if (!overlap
) subj
.contour
[s
].num_vertices
= -subj
.contour
[s
].num_vertices
;
1038 ===========================================================================
1040 ===========================================================================
1043 import core
.stdc
.stdio
: FILE
;
1045 public void gpc_read_polygon() (FILE
* fp
, bool read_hole_flags
, ref gpc_polygon p
) {
1046 import core
.stdc
.stdio
: fscanf
;
1047 fscanf(fp
, "%d", &(p
.num_contours
));
1048 p
.hole
= MALLOC
!int(p
.num_contours
);
1049 p
.contour
= MALLOC
!gpc_vertex_list(p
.num_contours
);
1050 foreach (immutable int c
; 0..p
.num_contours
) {
1051 fscanf(fp
, "%d", &(p
.contour
[c
].num_vertices
));
1052 if (read_hole_flags
) {
1053 fscanf(fp
, "%d", &(p
.hole
[c
]));
1055 p
.hole
[c
] = false; // Assume all contours to be external
1057 p
.contour
[c
].vertex
= MALLOC
!gpc_vertex(p
.contour
[c
].num_vertices
);
1058 foreach (immutable int v
; 0..p
.contour
[c
].num_vertices
) {
1059 fscanf(fp
, "%lf %lf", &(p
.contour
[c
].vertex
[v
].x
), &(p
.contour
[c
].vertex
[v
].y
));
1064 public void gpc_write_polygon() (FILE
* fp
, bool write_hole_flags
, in ref gpc_polygon p
) {
1065 import core
.stdc
.stdio
: fprintf
;
1066 fprintf(fp
, "%d\n", p
.num_contours
);
1067 foreach (immutable int c
; 0..p
.num_contours
) {
1068 fprintf(fp
, "%d\n", p
.contour
[c
].num_vertices
);
1069 if (write_hole_flags
) fprintf(fp
, "%d\n", p
.hole
[c
]);
1070 foreach (immutable int v
; 0..p
.contour
[c
].num_vertices
) {
1071 fprintf(fp
, "% .*lf % .*lf\n", double.dig
, p
.contour
[c
].vertex
[v
].x
, double.dig
, p
.contour
[c
].vertex
[v
].y
);
1077 /// Frees allocated polygon memory. It is safe to call it on empty (but initialized) polygon.
1078 public void gpc_free_polygon (ref gpc_polygon p
) {
1079 foreach (immutable int c
; 0..p
.num_contours
) FREE(p
.contour
[c
].vertex
);
1085 /** Add new contour to the existing polygon.
1087 * This function copies `new_contour` contents. But it reallocates quite inefficiently,
1088 * so you'd better build polys yourself.
1090 * Contours with less than three points will not be added.
1092 * Returns `true` if contour contains three or more points (i.e. it was added).
1094 public bool gpc_add_contour (ref gpc_polygon p
, const(gpc_vertex
)[] new_contour
, bool hole
=false) {
1095 import core
.stdc
.string
: memcpy
;
1097 if (new_contour
.length
< 3) return false;
1098 if (new_contour
.length
> int.max
/8) assert(0, "out of memory");
1100 int c
= p
.num_contours
;
1102 // allocate hole array with one more item
1103 REALLOC(p
.hole
, c
+1);
1105 // allocate contour array with one more item
1106 REALLOC(p
.contour
, c
+1);
1108 // copy the new contour and hole onto the end of the extended arrays
1110 p
.contour
[c
].num_vertices
= cast(int)new_contour
.length
;
1111 p
.contour
[c
].vertex
= MALLOC
!gpc_vertex(cast(uint)new_contour
.length
);
1112 memcpy(p
.contour
[c
].vertex
, new_contour
.ptr
, cast(uint)new_contour
.length
*gpc_vertex
.sizeof
);
1114 // Update the polygon information
1121 /** Calculates clipping.
1123 * [result] will be overwritten (so old contents won't be freed, and it may be uninitialized at all).
1125 public void gpc_polygon_clip (GPC op
, ref gpc_polygon subj
, ref gpc_polygon clip
, ref gpc_polygon result
) {
1126 sb_tree
* sbtree
= null;
1127 it_node
* it
= null, intersect
;
1128 edge_node
* edge
, prev_edge
, next_edge
, succ_edge
, e0
, e1
;
1129 edge_node
* aet
= null, c_heap
= null, s_heap
= null;
1130 lmt_node
* lmt
= null, local_min
;
1131 polygon_node
* out_poly
= null, p
, q
, poly
, npoly
, cf
= null;
1132 vertex_node
* vtx
, nv
;
1135 int[2] parity
= [LEFT
, LEFT
];
1136 int c
, v
, contributing
, scanbeam
= 0, sbt_entries
= 0;
1137 int vclass
, bl
, br
, tl
, tr
;
1139 double xb
, px
, yb
, yt
, dy
, ix
, iy
;
1141 // Test for trivial NULL result cases
1142 if ((subj
.num_contours
== 0 && clip
.num_contours
== 0) ||
1143 (subj
.num_contours
== 0 && (op
== GPC
.Int || op
== GPC
.Diff
)) ||
1144 (clip
.num_contours
== 0 && op
== GPC
.Int
))
1146 result
.num_contours
= 0;
1148 result
.contour
= null;
1152 // Identify potentialy contributing contours
1153 if ((op
== GPC
.Int || op
== GPC
.Diff
) && subj
.num_contours
> 0 && clip
.num_contours
> 0) minimax_test(&subj
, &clip
, op
);
1156 if (subj
.num_contours
> 0) s_heap
= build_lmt(&lmt
, &sbtree
, &sbt_entries
, &subj
, SUBJ
, op
);
1157 if (clip
.num_contours
> 0) c_heap
= build_lmt(&lmt
, &sbtree
, &sbt_entries
, &clip
, CLIP
, op
);
1159 // Return a NULL result if no contours contribute
1161 result
.num_contours
= 0;
1163 result
.contour
= null;
1170 // Build scanbeam table from scanbeam tree
1171 sbt
= MALLOC
!double(sbt_entries
);
1172 build_sbt(&scanbeam
, sbt
, sbtree
);
1174 free_sbtree(&sbtree
);
1176 // Allow pointer re-use without causing memory leak
1177 if (&subj
is &result
) gpc_free_polygon(subj
);
1178 if (&clip
is &result
) gpc_free_polygon(clip
);
1180 // Invert clip polygon for difference operation
1181 if (op
== GPC
.Diff
) parity
[CLIP
] = RIGHT
;
1185 // Process each scanbeam
1186 while (scanbeam
< sbt_entries
) {
1187 // Set yb and yt to the bottom and top of the scanbeam
1188 yb
= sbt
[scanbeam
++];
1189 if (scanbeam
< sbt_entries
) {
1194 // === SCANBEAM BOUNDARY PROCESSING ================================
1196 // If LMT node corresponding to yb exists
1198 if (local_min
.y
== yb
) {
1199 // Add edges starting at this local minimum to the AET
1200 for (edge
= local_min
.first_bound
; edge
!is null; edge
= edge
.next_bound
) add_edge_to_aet(&aet
, edge
, null);
1201 local_min
= local_min
.next
;
1205 // Set dummy previous x value
1208 // Create bundles within AET
1212 // Set up bundle fields of first edge
1213 aet
.bundle
[ABOVE
][ aet
.type
] = (aet
.top
.y
!= yb
);
1214 aet
.bundle
[ABOVE
][!aet
.type
] = false;
1215 aet
.bstate
[ABOVE
] = UNBUNDLED
;
1217 for (next_edge
= aet
.next
; next_edge
!is null; next_edge
= next_edge
.next
) {
1218 // Set up bundle fields of next edge
1219 next_edge
.bundle
[ABOVE
][ next_edge
.type
] = (next_edge
.top
.y
!= yb
);
1220 next_edge
.bundle
[ABOVE
][!next_edge
.type
] = false;
1221 next_edge
.bstate
[ABOVE
] = UNBUNDLED
;
1223 // Bundle edges above the scanbeam boundary if they coincide
1224 if (next_edge
.bundle
[ABOVE
][next_edge
.type
]) {
1225 if (EQ(e0
.xb
, next_edge
.xb
) && EQ(e0
.dx
, next_edge
.dx
) && e0
.top
.y
!= yb
) {
1226 next_edge
.bundle
[ABOVE
][ next_edge
.type
] ^
= e0
.bundle
[ABOVE
][ next_edge
.type
];
1227 next_edge
.bundle
[ABOVE
][!next_edge
.type
] = e0
.bundle
[ABOVE
][!next_edge
.type
];
1228 next_edge
.bstate
[ABOVE
] = BUNDLE_HEAD
;
1229 e0
.bundle
[ABOVE
][CLIP
] = false;
1230 e0
.bundle
[ABOVE
][SUBJ
] = false;
1231 e0
.bstate
[ABOVE
] = BUNDLE_TAIL
;
1240 // Process each edge at this scanbeam boundary
1241 for (edge
= aet
; edge
!is null; edge
= edge
.next
) {
1242 exists
[CLIP
] = edge
.bundle
[ABOVE
][CLIP
] + (edge
.bundle
[BELOW
][CLIP
] << 1);
1243 exists
[SUBJ
] = edge
.bundle
[ABOVE
][SUBJ
] + (edge
.bundle
[BELOW
][SUBJ
] << 1);
1245 if (exists
[CLIP
] || exists
[SUBJ
]) {
1247 edge
.bside
[CLIP
] = parity
[CLIP
];
1248 edge
.bside
[SUBJ
] = parity
[SUBJ
];
1250 // Determine contributing status and quadrant occupancies
1254 contributing
= (exists
[CLIP
] && (parity
[SUBJ
] || horiz
[SUBJ
])) ||
(exists
[SUBJ
] && (parity
[CLIP
] || horiz
[CLIP
])) ||
(exists
[CLIP
] && exists
[SUBJ
] && (parity
[CLIP
] == parity
[SUBJ
]));
1255 br
= (parity
[CLIP
]) && (parity
[SUBJ
]);
1256 bl
= (parity
[CLIP
] ^ edge
.bundle
[ABOVE
][CLIP
]) && (parity
[SUBJ
] ^ edge
.bundle
[ABOVE
][SUBJ
]);
1257 tr
= (parity
[CLIP
] ^
(horiz
[CLIP
] != NH
)) && (parity
[SUBJ
] ^
(horiz
[SUBJ
] != NH
));
1258 tl
= (parity
[CLIP
] ^
(horiz
[CLIP
] != NH
) ^ edge
.bundle
[BELOW
][CLIP
]) && (parity
[SUBJ
] ^
(horiz
[SUBJ
] != NH
) ^ edge
.bundle
[BELOW
][SUBJ
]);
1261 contributing
= exists
[CLIP
] || exists
[SUBJ
];
1262 br
= (parity
[CLIP
]) ^
(parity
[SUBJ
]);
1263 bl
= (parity
[CLIP
] ^ edge
.bundle
[ABOVE
][CLIP
]) ^
(parity
[SUBJ
] ^ edge
.bundle
[ABOVE
][SUBJ
]);
1264 tr
= (parity
[CLIP
] ^
(horiz
[CLIP
] != NH
)) ^
(parity
[SUBJ
] ^
(horiz
[SUBJ
] != NH
));
1265 tl
= (parity
[CLIP
] ^
(horiz
[CLIP
] != NH
) ^ edge
.bundle
[BELOW
][CLIP
]) ^
(parity
[SUBJ
] ^
(horiz
[SUBJ
] != NH
) ^ edge
.bundle
[BELOW
][SUBJ
]);
1268 contributing
= (exists
[CLIP
] && (!parity
[SUBJ
] || horiz
[SUBJ
])) ||
(exists
[SUBJ
] && (!parity
[CLIP
] || horiz
[CLIP
])) ||
(exists
[CLIP
] && exists
[SUBJ
] && (parity
[CLIP
] == parity
[SUBJ
]));
1269 br
= (parity
[CLIP
]) ||
(parity
[SUBJ
]);
1270 bl
= (parity
[CLIP
] ^ edge
.bundle
[ABOVE
][CLIP
]) ||
(parity
[SUBJ
] ^ edge
.bundle
[ABOVE
][SUBJ
]);
1271 tr
= (parity
[CLIP
] ^
(horiz
[CLIP
] != NH
)) ||
(parity
[SUBJ
] ^
(horiz
[SUBJ
] != NH
));
1272 tl
= (parity
[CLIP
] ^
(horiz
[CLIP
] != NH
) ^ edge
.bundle
[BELOW
][CLIP
]) ||
(parity
[SUBJ
] ^
(horiz
[SUBJ
] != NH
) ^ edge
.bundle
[BELOW
][SUBJ
]);
1278 parity
[CLIP
] ^
= edge
.bundle
[ABOVE
][CLIP
];
1279 parity
[SUBJ
] ^
= edge
.bundle
[ABOVE
][SUBJ
];
1281 // Update horizontal state
1282 if (exists
[CLIP
]) horiz
[CLIP
] = next_h_state
[horiz
[CLIP
]][((exists
[CLIP
] - 1) << 1) + parity
[CLIP
]];
1283 if (exists
[SUBJ
]) horiz
[SUBJ
] = next_h_state
[horiz
[SUBJ
]][((exists
[SUBJ
] - 1) << 1) + parity
[SUBJ
]];
1285 vclass
= tr
+ (tl
<< 1) + (br
<< 2) + (bl
<< 3);
1293 add_local_min(&out_poly
, edge
, xb
, yb
);
1295 cf
= edge
.outp
[ABOVE
];
1299 add_right(cf
, xb
, yb
);
1302 edge
.outp
[ABOVE
]= cf
;
1306 add_left(edge
.outp
[BELOW
], xb
, yb
);
1308 cf
= edge
.outp
[BELOW
];
1312 add_left(cf
, xb
, yb
);
1315 merge_right(cf
, edge
.outp
[BELOW
], out_poly
);
1320 add_left(cf
, xb
, yb
);
1323 edge
.outp
[ABOVE
] = cf
;
1327 add_right(edge
.outp
[BELOW
], xb
, yb
);
1329 cf
= edge
.outp
[BELOW
];
1330 edge
.outp
[BELOW
] = null;
1334 add_right(cf
, xb
, yb
);
1337 merge_left(cf
, edge
.outp
[BELOW
], out_poly
);
1339 edge
.outp
[BELOW
] = null;
1343 add_right(cf
, xb
, yb
);
1346 merge_left(cf
, edge
.outp
[BELOW
], out_poly
);
1347 edge
.outp
[BELOW
] = null;
1348 add_local_min(&out_poly
, edge
, xb
, yb
);
1349 cf
= edge
.outp
[ABOVE
];
1353 add_left(cf
, xb
, yb
);
1356 merge_right(cf
, edge
.outp
[BELOW
], out_poly
);
1357 edge
.outp
[BELOW
] = null;
1358 add_local_min(&out_poly
, edge
, xb
, yb
);
1359 cf
= edge
.outp
[ABOVE
];
1362 if (edge
.bot
.y
== yb
) add_left(edge
.outp
[BELOW
], xb
, yb
);
1363 edge
.outp
[ABOVE
] = edge
.outp
[BELOW
];
1367 if (edge
.bot
.y
== yb
) add_right(edge
.outp
[BELOW
], xb
, yb
);
1368 edge
.outp
[ABOVE
] = edge
.outp
[BELOW
];
1374 } // End of contributing conditional
1375 } // End of edge exists conditional
1376 } // End of AET loop
1378 // Delete terminating edges from the AET, otherwise compute xt
1379 for (edge
= aet
; edge
!is null; edge
= edge
.next
) {
1380 if (edge
.top
.y
== yb
) {
1381 prev_edge
= edge
.prev
;
1382 next_edge
= edge
.next
;
1383 if (prev_edge
) prev_edge
.next
= next_edge
; else aet
= next_edge
;
1384 if (next_edge
) next_edge
.prev
= prev_edge
;
1386 // Copy bundle head state to the adjacent tail edge if required
1387 if ((edge
.bstate
[BELOW
] == BUNDLE_HEAD
) && prev_edge
) {
1388 if (prev_edge
.bstate
[BELOW
] == BUNDLE_TAIL
) {
1389 prev_edge
.outp
[BELOW
] = edge
.outp
[BELOW
];
1390 prev_edge
.bstate
[BELOW
] = UNBUNDLED
;
1391 if (prev_edge
.prev
) {
1392 if (prev_edge
.prev
.bstate
[BELOW
] == BUNDLE_TAIL
) prev_edge
.bstate
[BELOW
] = BUNDLE_HEAD
;
1397 if (edge
.top
.y
== yt
) {
1398 edge
.xt
= edge
.top
.x
;
1400 edge
.xt
= edge
.bot
.x
+ edge
.dx
* (yt
- edge
.bot
.y
);
1405 if (scanbeam
< sbt_entries
) {
1406 // === SCANBEAM INTERIOR PROCESSING ==============================
1408 build_intersection_table(&it
, aet
, dy
);
1410 // Process each node in the intersection table
1411 for (intersect
= it
; intersect
; intersect
= intersect
.next
) {
1412 e0
= intersect
.ie
[0];
1413 e1
= intersect
.ie
[1];
1415 // Only generate output for contributing intersections
1416 if ((e0
.bundle
[ABOVE
][CLIP
] || e0
.bundle
[ABOVE
][SUBJ
]) && (e1
.bundle
[ABOVE
][CLIP
] || e1
.bundle
[ABOVE
][SUBJ
])) {
1419 ix
= intersect
.point
.x
;
1420 iy
= intersect
.point
.y
+ yb
;
1422 inn
[CLIP
] = (e0
.bundle
[ABOVE
][CLIP
] && !e0
.bside
[CLIP
]) ||
(e1
.bundle
[ABOVE
][CLIP
] && e1
.bside
[CLIP
]) ||
(!e0
.bundle
[ABOVE
][CLIP
] && !e1
.bundle
[ABOVE
][CLIP
] && e0
.bside
[CLIP
] && e1
.bside
[CLIP
]);
1423 inn
[SUBJ
] = (e0
.bundle
[ABOVE
][SUBJ
] && !e0
.bside
[SUBJ
]) ||
(e1
.bundle
[ABOVE
][SUBJ
] && e1
.bside
[SUBJ
]) ||
(!e0
.bundle
[ABOVE
][SUBJ
] && !e1
.bundle
[ABOVE
][SUBJ
] && e0
.bside
[SUBJ
] && e1
.bside
[SUBJ
]);
1425 // Determine quadrant occupancies
1429 tr
= (inn
[CLIP
]) && (inn
[SUBJ
]);
1430 tl
= (inn
[CLIP
] ^ e1
.bundle
[ABOVE
][CLIP
]) && (inn
[SUBJ
] ^ e1
.bundle
[ABOVE
][SUBJ
]);
1431 br
= (inn
[CLIP
] ^ e0
.bundle
[ABOVE
][CLIP
]) && (inn
[SUBJ
] ^ e0
.bundle
[ABOVE
][SUBJ
]);
1432 bl
= (inn
[CLIP
] ^ e1
.bundle
[ABOVE
][CLIP
] ^ e0
.bundle
[ABOVE
][CLIP
]) && (inn
[SUBJ
] ^ e1
.bundle
[ABOVE
][SUBJ
] ^ e0
.bundle
[ABOVE
][SUBJ
]);
1435 tr
= (inn
[CLIP
]) ^
(inn
[SUBJ
]);
1436 tl
= (inn
[CLIP
] ^ e1
.bundle
[ABOVE
][CLIP
]) ^
(inn
[SUBJ
] ^ e1
.bundle
[ABOVE
][SUBJ
]);
1437 br
= (inn
[CLIP
] ^ e0
.bundle
[ABOVE
][CLIP
]) ^
(inn
[SUBJ
] ^ e0
.bundle
[ABOVE
][SUBJ
]);
1438 bl
= (inn
[CLIP
] ^ e1
.bundle
[ABOVE
][CLIP
] ^ e0
.bundle
[ABOVE
][CLIP
]) ^
(inn
[SUBJ
] ^ e1
.bundle
[ABOVE
][SUBJ
] ^ e0
.bundle
[ABOVE
][SUBJ
]);
1441 tr
= (inn
[CLIP
]) ||
(inn
[SUBJ
]);
1442 tl
= (inn
[CLIP
] ^ e1
.bundle
[ABOVE
][CLIP
]) ||
(inn
[SUBJ
] ^ e1
.bundle
[ABOVE
][SUBJ
]);
1443 br
= (inn
[CLIP
] ^ e0
.bundle
[ABOVE
][CLIP
]) ||
(inn
[SUBJ
] ^ e0
.bundle
[ABOVE
][SUBJ
]);
1444 bl
= (inn
[CLIP
] ^ e1
.bundle
[ABOVE
][CLIP
] ^ e0
.bundle
[ABOVE
][CLIP
]) ||
(inn
[SUBJ
] ^ e1
.bundle
[ABOVE
][SUBJ
] ^ e0
.bundle
[ABOVE
][SUBJ
]);
1449 vclass
= tr
+ (tl
<< 1) + (br
<< 2) + (bl
<< 3);
1453 add_local_min(&out_poly
, e0
, ix
, iy
);
1454 e1
.outp
[ABOVE
] = e0
.outp
[ABOVE
];
1458 add_right(p
, ix
, iy
);
1460 e0
.outp
[ABOVE
] = null;
1465 add_left(q
, ix
, iy
);
1467 e1
.outp
[ABOVE
] = null;
1472 add_left(p
, ix
, iy
);
1473 merge_right(p
, q
, out_poly
);
1474 e0
.outp
[ABOVE
] = null;
1475 e1
.outp
[ABOVE
] = null;
1479 add_local_min(&out_poly
, e0
, ix
, iy
);
1480 e1
.outp
[ABOVE
] = e0
.outp
[ABOVE
];
1484 add_left(p
, ix
, iy
);
1486 e0
.outp
[ABOVE
] = null;
1491 add_right(q
, ix
, iy
);
1493 e1
.outp
[ABOVE
] = null;
1498 add_right(p
, ix
, iy
);
1499 merge_left(p
, q
, out_poly
);
1500 e0
.outp
[ABOVE
] = null;
1501 e1
.outp
[ABOVE
] = null;
1506 add_right(p
, ix
, iy
);
1507 merge_left(p
, q
, out_poly
);
1508 add_local_min(&out_poly
, e0
, ix
, iy
);
1509 e1
.outp
[ABOVE
] = e0
.outp
[ABOVE
];
1514 add_left(p
, ix
, iy
);
1515 merge_right(p
, q
, out_poly
);
1516 add_local_min(&out_poly
, e0
, ix
, iy
);
1517 e1
.outp
[ABOVE
] = e0
.outp
[ABOVE
];
1523 } // End of contributing intersection conditional
1525 // Swap bundle sides in response to edge crossing
1526 if (e0
.bundle
[ABOVE
][CLIP
]) e1
.bside
[CLIP
] = !e1
.bside
[CLIP
];
1527 if (e1
.bundle
[ABOVE
][CLIP
]) e0
.bside
[CLIP
] = !e0
.bside
[CLIP
];
1528 if (e0
.bundle
[ABOVE
][SUBJ
]) e1
.bside
[SUBJ
] = !e1
.bside
[SUBJ
];
1529 if (e1
.bundle
[ABOVE
][SUBJ
]) e0
.bside
[SUBJ
] = !e0
.bside
[SUBJ
];
1531 // Swap the edge bundles in the aet
1532 swap_intersecting_edge_bundles(&aet
, intersect
);
1535 // Prepare for next scanbeam
1536 for (edge
= aet
; edge
!is null; edge
= next_edge
) {
1537 next_edge
= edge
.next
;
1538 succ_edge
= edge
.succ
;
1540 if (edge
.top
.y
== yt
&& succ_edge
) {
1541 // Replace AET edge by its successor
1542 succ_edge
.outp
[BELOW
] = edge
.outp
[ABOVE
];
1543 succ_edge
.bstate
[BELOW
] = edge
.bstate
[ABOVE
];
1544 succ_edge
.bundle
[BELOW
][CLIP
] = edge
.bundle
[ABOVE
][CLIP
];
1545 succ_edge
.bundle
[BELOW
][SUBJ
] = edge
.bundle
[ABOVE
][SUBJ
];
1546 prev_edge
= edge
.prev
;
1547 if (prev_edge
) prev_edge
.next
= succ_edge
; else aet
= succ_edge
;
1548 if (next_edge
) next_edge
.prev
= succ_edge
;
1549 succ_edge
.prev
= prev_edge
;
1550 succ_edge
.next
= next_edge
;
1553 edge
.outp
[BELOW
] = edge
.outp
[ABOVE
];
1554 edge
.bstate
[BELOW
] = edge
.bstate
[ABOVE
];
1555 edge
.bundle
[BELOW
][CLIP
] = edge
.bundle
[ABOVE
][CLIP
];
1556 edge
.bundle
[BELOW
][SUBJ
] = edge
.bundle
[ABOVE
][SUBJ
];
1559 edge
.outp
[ABOVE
] = null;
1562 } // === END OF SCANBEAM PROCESSING ==================================
1564 // Generate result polygon from out_poly
1565 result
.contour
= null;
1567 result
.num_contours
= count_contours(out_poly
);
1568 if (result
.num_contours
> 0) {
1569 result
.hole
= MALLOC
!int(result
.num_contours
);
1570 result
.contour
= MALLOC
!gpc_vertex_list(result
.num_contours
);
1572 for (poly
= out_poly
; poly
!is null; poly
= npoly
) {
1575 result
.hole
[c
] = poly
.proxy
.hole
;
1576 result
.contour
[c
].num_vertices
= poly
.active
;
1577 result
.contour
[c
].vertex
= MALLOC
!gpc_vertex(result
.contour
[c
].num_vertices
);
1578 v
= result
.contour
[c
].num_vertices
-1;
1579 for (vtx
= poly
.proxy
.v
[LEFT
]; vtx
!is null; vtx
= nv
) {
1581 result
.contour
[c
].vertex
[v
].x
= vtx
.x
;
1582 result
.contour
[c
].vertex
[v
].y
= vtx
.y
;
1591 for (poly
= out_poly
; poly
!is null; poly
= npoly
) {
1606 /// Frees allocated tristrip memory. It is safe to call it on empty (but initialized) tristrip.
1607 public void gpc_free_tristrip (ref gpc_tristrip t
) {
1608 foreach (immutable int s
; 0..t
.num_strips
) FREE(t
.strip
[s
].vertex
);
1614 /** Converts polygon to triangle strip (tristrip).
1616 * [result] will be overwritten (so old contents won't be freed, and it may be uninitialized at all).
1618 public void gpc_polygon_to_tristrip (ref gpc_polygon s
, ref gpc_tristrip result
) {
1623 gpc_tristrip_clip(GPC
.Diff
, s
, c
, result
);
1627 /** Calculates clipping, returns result as triangle strip (tristrip).
1629 * [result] will be overwritten (so old contents won't be freed, and it may be uninitialized at all).
1631 public void gpc_tristrip_clip (GPC op
, ref gpc_polygon subj
, ref gpc_polygon clip
, ref gpc_tristrip result
) {
1632 sb_tree
* sbtree
= null;
1633 it_node
* it
= null, intersect
;
1634 edge_node
* edge
, prev_edge
, next_edge
, succ_edge
, e0
, e1
;
1635 edge_node
* aet
= null, c_heap
= null, s_heap
= null, cf
;
1636 lmt_node
* lmt
= null, local_min
;
1637 polygon_node
* tlist
= null, tn
, tnn
, p
, q
;
1638 vertex_node
* lt
, ltn
, rt
, rtn
;
1642 int[2] parity
= [LEFT
, LEFT
];
1643 int s
, v
, contributing
, scanbeam
= 0, sbt_entries
= 0;
1644 int vclass
, bl
, br
, tl
, tr
;
1646 double xb
, px
, nx
, yb
, yt
, dy
, ix
, iy
;
1648 // Test for trivial NULL result cases
1649 if ((subj
.num_contours
== 0 && clip
.num_contours
== 0) ||
1650 (subj
.num_contours
== 0 && (op
== GPC
.Int || op
== GPC
.Diff
)) ||
1651 (clip
.num_contours
== 0 && op
== GPC
.Int
))
1653 result
.num_strips
= 0;
1654 result
.strip
= null;
1658 // Identify potentialy contributing contours
1659 if ((op
== GPC
.Int || op
== GPC
.Diff
) && subj
.num_contours
> 0 && clip
.num_contours
> 0) minimax_test(&subj
, &clip
, op
);
1662 if (subj
.num_contours
> 0) s_heap
= build_lmt(&lmt
, &sbtree
, &sbt_entries
, &subj
, SUBJ
, op
);
1663 if (clip
.num_contours
> 0) c_heap
= build_lmt(&lmt
, &sbtree
, &sbt_entries
, &clip
, CLIP
, op
);
1665 // Return a NULL result if no contours contribute
1667 result
.num_strips
= 0;
1668 result
.strip
= null;
1675 // Build scanbeam table from scanbeam tree
1676 sbt
= MALLOC
!double(sbt_entries
);
1677 build_sbt(&scanbeam
, sbt
, sbtree
);
1679 free_sbtree(&sbtree
);
1681 // Invert clip polygon for difference operation
1682 if (op
== GPC
.Diff
) parity
[CLIP
] = RIGHT
;
1686 // Process each scanbeam
1687 while (scanbeam
< sbt_entries
) {
1688 // Set yb and yt to the bottom and top of the scanbeam
1689 yb
= sbt
[scanbeam
++];
1690 if (scanbeam
< sbt_entries
) {
1695 // === SCANBEAM BOUNDARY PROCESSING ================================
1697 // If LMT node corresponding to yb exists
1699 if (local_min
.y
== yb
) {
1700 // Add edges starting at this local minimum to the AET
1701 for (edge
= local_min
.first_bound
; edge
!is null; edge
= edge
.next_bound
) add_edge_to_aet(&aet
, edge
, null);
1702 local_min
= local_min
.next
;
1706 // Set dummy previous x value
1709 // Create bundles within AET
1713 // Set up bundle fields of first edge
1714 aet
.bundle
[ABOVE
][ aet
.type
] = (aet
.top
.y
!= yb
);
1715 aet
.bundle
[ABOVE
][!aet
.type
] = false;
1716 aet
.bstate
[ABOVE
] = UNBUNDLED
;
1718 for (next_edge
= aet
.next
; next_edge
!is null; next_edge
= next_edge
.next
) {
1719 // Set up bundle fields of next edge
1720 next_edge
.bundle
[ABOVE
][next_edge
.type
] = (next_edge
.top
.y
!= yb
);
1721 next_edge
.bundle
[ABOVE
][!next_edge
.type
] = false;
1722 next_edge
.bstate
[ABOVE
] = UNBUNDLED
;
1724 // Bundle edges above the scanbeam boundary if they coincide
1725 if (next_edge
.bundle
[ABOVE
][next_edge
.type
]) {
1726 if (EQ(e0
.xb
, next_edge
.xb
) && EQ(e0
.dx
, next_edge
.dx
) && e0
.top
.y
!= yb
) {
1727 next_edge
.bundle
[ABOVE
][ next_edge
.type
] ^
= e0
.bundle
[ABOVE
][ next_edge
.type
];
1728 next_edge
.bundle
[ABOVE
][!next_edge
.type
] = e0
.bundle
[ABOVE
][!next_edge
.type
];
1729 next_edge
.bstate
[ABOVE
] = BUNDLE_HEAD
;
1730 e0
.bundle
[ABOVE
][CLIP
] = false;
1731 e0
.bundle
[ABOVE
][SUBJ
] = false;
1732 e0
.bstate
[ABOVE
] = BUNDLE_TAIL
;
1741 // Process each edge at this scanbeam boundary
1742 for (edge
= aet
; edge
!is null; edge
= edge
.next
) {
1743 exists
[CLIP
] = edge
.bundle
[ABOVE
][CLIP
] + (edge
.bundle
[BELOW
][CLIP
] << 1);
1744 exists
[SUBJ
] = edge
.bundle
[ABOVE
][SUBJ
] + (edge
.bundle
[BELOW
][SUBJ
] << 1);
1746 if (exists
[CLIP
] || exists
[SUBJ
]) {
1748 edge
.bside
[CLIP
] = parity
[CLIP
];
1749 edge
.bside
[SUBJ
] = parity
[SUBJ
];
1751 // Determine contributing status and quadrant occupancies
1755 contributing
= (exists
[CLIP
] && (parity
[SUBJ
] || horiz
[SUBJ
])) ||
(exists
[SUBJ
] && (parity
[CLIP
] || horiz
[CLIP
])) ||
(exists
[CLIP
] && exists
[SUBJ
] && (parity
[CLIP
] == parity
[SUBJ
]));
1756 br
= (parity
[CLIP
]) && (parity
[SUBJ
]);
1757 bl
= (parity
[CLIP
] ^ edge
.bundle
[ABOVE
][CLIP
]) && (parity
[SUBJ
] ^ edge
.bundle
[ABOVE
][SUBJ
]);
1758 tr
= (parity
[CLIP
] ^
(horiz
[CLIP
] != NH
)) && (parity
[SUBJ
] ^
(horiz
[SUBJ
] != NH
));
1759 tl
= (parity
[CLIP
] ^
(horiz
[CLIP
] != NH
) ^ edge
.bundle
[BELOW
][CLIP
]) && (parity
[SUBJ
] ^
(horiz
[SUBJ
] != NH
) ^ edge
.bundle
[BELOW
][SUBJ
]);
1762 contributing
= exists
[CLIP
] || exists
[SUBJ
];
1763 br
= (parity
[CLIP
]) ^
(parity
[SUBJ
]);
1764 bl
= (parity
[CLIP
] ^ edge
.bundle
[ABOVE
][CLIP
]) ^
(parity
[SUBJ
] ^ edge
.bundle
[ABOVE
][SUBJ
]);
1765 tr
= (parity
[CLIP
] ^
(horiz
[CLIP
] != NH
)) ^
(parity
[SUBJ
] ^
(horiz
[SUBJ
] != NH
));
1766 tl
= (parity
[CLIP
] ^
(horiz
[CLIP
] != NH
) ^ edge
.bundle
[BELOW
][CLIP
]) ^
(parity
[SUBJ
] ^
(horiz
[SUBJ
] != NH
) ^ edge
.bundle
[BELOW
][SUBJ
]);
1769 contributing
= (exists
[CLIP
] && (!parity
[SUBJ
] || horiz
[SUBJ
])) ||
(exists
[SUBJ
] && (!parity
[CLIP
] || horiz
[CLIP
])) ||
(exists
[CLIP
] && exists
[SUBJ
] && (parity
[CLIP
] == parity
[SUBJ
]));
1770 br
= (parity
[CLIP
]) ||
(parity
[SUBJ
]);
1771 bl
= (parity
[CLIP
] ^ edge
.bundle
[ABOVE
][CLIP
]) ||
(parity
[SUBJ
] ^ edge
.bundle
[ABOVE
][SUBJ
]);
1772 tr
= (parity
[CLIP
] ^
(horiz
[CLIP
] != NH
)) ||
(parity
[SUBJ
] ^
(horiz
[SUBJ
] != NH
));
1773 tl
= (parity
[CLIP
] ^
(horiz
[CLIP
] != NH
) ^ edge
.bundle
[BELOW
][CLIP
]) ||
(parity
[SUBJ
] ^
(horiz
[SUBJ
] != NH
) ^ edge
.bundle
[BELOW
][SUBJ
]);
1779 parity
[CLIP
] ^
= edge
.bundle
[ABOVE
][CLIP
];
1780 parity
[SUBJ
] ^
= edge
.bundle
[ABOVE
][SUBJ
];
1782 // Update horizontal state
1783 if (exists
[CLIP
]) horiz
[CLIP
] = next_h_state
[horiz
[CLIP
]][((exists
[CLIP
] - 1) << 1) + parity
[CLIP
]];
1784 if (exists
[SUBJ
]) horiz
[SUBJ
] = next_h_state
[horiz
[SUBJ
]][((exists
[SUBJ
] - 1) << 1) + parity
[SUBJ
]];
1786 vclass
= tr
+ (tl
<< 1) + (br
<< 2) + (bl
<< 3);
1793 new_tristrip(&tlist
, edge
, xb
, yb
);
1797 edge
.outp
[ABOVE
] = cf
.outp
[ABOVE
];
1798 if (xb
!= cf
.xb
) VERTEX(edge
, ABOVE
, RIGHT
, xb
, yb
);
1802 VERTEX(edge
, BELOW
, LEFT
, xb
, yb
);
1803 edge
.outp
[ABOVE
] = null;
1807 if (xb
!= cf
.xb
) VERTEX(edge
, BELOW
, RIGHT
, xb
, yb
);
1808 edge
.outp
[ABOVE
] = null;
1813 if (cf
.bot
.y
!= yb
) VERTEX(cf
, BELOW
, LEFT
, cf
.xb
, yb
);
1814 new_tristrip(&tlist
, cf
, cf
.xb
, yb
);
1816 edge
.outp
[ABOVE
] = cf
.outp
[ABOVE
];
1817 VERTEX(edge
, ABOVE
, RIGHT
, xb
, yb
);
1820 new_tristrip(&tlist
, edge
, xb
, yb
);
1826 if (cf
.bot
.y
!= yb
) VERTEX(cf
, BELOW
, LEFT
, cf
.xb
, yb
);
1827 new_tristrip(&tlist
, cf
, cf
.xb
, yb
);
1829 VERTEX(edge
, BELOW
, RIGHT
, xb
, yb
);
1830 edge
.outp
[ABOVE
] = null;
1833 VERTEX(edge
, BELOW
, LEFT
, xb
, yb
);
1834 edge
.outp
[ABOVE
] = null;
1838 VERTEX(edge
, BELOW
, LEFT
, xb
, yb
);
1839 edge
.outp
[ABOVE
] = cf
.outp
[ABOVE
];
1840 if (xb
!= cf
.xb
) VERTEX(cf
, ABOVE
, RIGHT
, xb
, yb
);
1844 VERTEX(edge
, BELOW
, RIGHT
, xb
, yb
);
1845 edge
.outp
[ABOVE
] = null;
1846 new_tristrip(&tlist
, edge
, xb
, yb
);
1850 if (edge
.bot
.y
== yb
) VERTEX(edge
, BELOW
, LEFT
, xb
, yb
);
1851 edge
.outp
[ABOVE
] = edge
.outp
[BELOW
];
1856 edge
.outp
[ABOVE
]= cf
.outp
[ABOVE
];
1858 if (cf
.bot
.y
== yb
) {
1859 VERTEX(edge
, BELOW
, RIGHT
, xb
, yb
);
1861 if (edge
.bot
.y
== yb
) {
1862 VERTEX(cf
, BELOW
, LEFT
, cf
.xb
, yb
);
1863 VERTEX(edge
, BELOW
, RIGHT
, xb
, yb
);
1867 VERTEX(edge
, BELOW
, RIGHT
, xb
, yb
);
1868 VERTEX(edge
, ABOVE
, RIGHT
, xb
, yb
);
1875 } // End of contributing conditional
1876 } // End of edge exists conditional
1877 } // End of AET loop
1879 // Delete terminating edges from the AET, otherwise compute xt
1880 for (edge
= aet
; edge
!is null; edge
= edge
.next
) {
1881 if (edge
.top
.y
== yb
) {
1882 prev_edge
= edge
.prev
;
1883 next_edge
= edge
.next
;
1884 if (prev_edge
) prev_edge
.next
= next_edge
; else aet
= next_edge
;
1885 if (next_edge
) next_edge
.prev
= prev_edge
;
1887 // Copy bundle head state to the adjacent tail edge if required
1888 if ((edge
.bstate
[BELOW
] == BUNDLE_HEAD
) && prev_edge
) {
1889 if (prev_edge
.bstate
[BELOW
] == BUNDLE_TAIL
) {
1890 prev_edge
.outp
[BELOW
] = edge
.outp
[BELOW
];
1891 prev_edge
.bstate
[BELOW
] = UNBUNDLED
;
1892 if (prev_edge
.prev
) {
1893 if (prev_edge
.prev
.bstate
[BELOW
] == BUNDLE_TAIL
) prev_edge
.bstate
[BELOW
] = BUNDLE_HEAD
;
1898 if (edge
.top
.y
== yt
) edge
.xt
= edge
.top
.x
; else edge
.xt
= edge
.bot
.x
+ edge
.dx
* (yt
- edge
.bot
.y
);
1902 if (scanbeam
< sbt_entries
) {
1903 // === SCANBEAM INTERIOR PROCESSING ==============================
1905 build_intersection_table(&it
, aet
, dy
);
1907 // Process each node in the intersection table
1908 for (intersect
= it
; intersect
!is null; intersect
= intersect
.next
) {
1909 e0
= intersect
.ie
[0];
1910 e1
= intersect
.ie
[1];
1912 // Only generate output for contributing intersections
1913 if ((e0
.bundle
[ABOVE
][CLIP
] || e0
.bundle
[ABOVE
][SUBJ
]) && (e1
.bundle
[ABOVE
][CLIP
] || e1
.bundle
[ABOVE
][SUBJ
])) {
1916 ix
= intersect
.point
.x
;
1917 iy
= intersect
.point
.y
+ yb
;
1919 inn
[CLIP
] = (e0
.bundle
[ABOVE
][CLIP
] && !e0
.bside
[CLIP
]) ||
(e1
.bundle
[ABOVE
][CLIP
] && e1
.bside
[CLIP
]) ||
(!e0
.bundle
[ABOVE
][CLIP
] && !e1
.bundle
[ABOVE
][CLIP
] && e0
.bside
[CLIP
] && e1
.bside
[CLIP
]);
1920 inn
[SUBJ
] = (e0
.bundle
[ABOVE
][SUBJ
] && !e0
.bside
[SUBJ
]) ||
(e1
.bundle
[ABOVE
][SUBJ
] && e1
.bside
[SUBJ
]) ||
(!e0
.bundle
[ABOVE
][SUBJ
] && !e1
.bundle
[ABOVE
][SUBJ
] && e0
.bside
[SUBJ
] && e1
.bside
[SUBJ
]);
1922 // Determine quadrant occupancies
1926 tr
= (inn
[CLIP
]) && (inn
[SUBJ
]);
1927 tl
= (inn
[CLIP
] ^ e1
.bundle
[ABOVE
][CLIP
]) && (inn
[SUBJ
] ^ e1
.bundle
[ABOVE
][SUBJ
]);
1928 br
= (inn
[CLIP
] ^ e0
.bundle
[ABOVE
][CLIP
]) && (inn
[SUBJ
] ^ e0
.bundle
[ABOVE
][SUBJ
]);
1929 bl
= (inn
[CLIP
] ^ e1
.bundle
[ABOVE
][CLIP
] ^ e0
.bundle
[ABOVE
][CLIP
]) && (inn
[SUBJ
] ^ e1
.bundle
[ABOVE
][SUBJ
] ^ e0
.bundle
[ABOVE
][SUBJ
]);
1932 tr
= (inn
[CLIP
]) ^
(inn
[SUBJ
]);
1933 tl
= (inn
[CLIP
] ^ e1
.bundle
[ABOVE
][CLIP
]) ^
(inn
[SUBJ
] ^ e1
.bundle
[ABOVE
][SUBJ
]);
1934 br
= (inn
[CLIP
] ^ e0
.bundle
[ABOVE
][CLIP
]) ^
(inn
[SUBJ
] ^ e0
.bundle
[ABOVE
][SUBJ
]);
1935 bl
= (inn
[CLIP
] ^ e1
.bundle
[ABOVE
][CLIP
] ^ e0
.bundle
[ABOVE
][CLIP
]) ^
(inn
[SUBJ
] ^ e1
.bundle
[ABOVE
][SUBJ
] ^ e0
.bundle
[ABOVE
][SUBJ
]);
1938 tr
= (inn
[CLIP
]) ||
(inn
[SUBJ
]);
1939 tl
= (inn
[CLIP
] ^ e1
.bundle
[ABOVE
][CLIP
]) ||
(inn
[SUBJ
] ^ e1
.bundle
[ABOVE
][SUBJ
]);
1940 br
= (inn
[CLIP
] ^ e0
.bundle
[ABOVE
][CLIP
]) ||
(inn
[SUBJ
] ^ e0
.bundle
[ABOVE
][SUBJ
]);
1941 bl
= (inn
[CLIP
] ^ e1
.bundle
[ABOVE
][CLIP
] ^ e0
.bundle
[ABOVE
][CLIP
]) ||
(inn
[SUBJ
] ^ e1
.bundle
[ABOVE
][SUBJ
] ^ e0
.bundle
[ABOVE
][SUBJ
]);
1946 vclass
= tr
+ (tl
<< 1) + (br
<< 2) + (bl
<< 3);
1950 new_tristrip(&tlist
, e1
, ix
, iy
);
1951 e0
.outp
[ABOVE
] = e1
.outp
[ABOVE
];
1955 P_EDGE(prev_edge
, e0
, ABOVE
, px
, iy
);
1956 VERTEX(prev_edge
, ABOVE
, LEFT
, px
, iy
);
1957 VERTEX(e0
, ABOVE
, RIGHT
, ix
, iy
);
1958 e1
.outp
[ABOVE
] = e0
.outp
[ABOVE
];
1959 e0
.outp
[ABOVE
] = null;
1964 N_EDGE(next_edge
, e1
, ABOVE
, nx
, iy
);
1965 VERTEX(e1
, ABOVE
, LEFT
, ix
, iy
);
1966 VERTEX(next_edge
, ABOVE
, RIGHT
, nx
, iy
);
1967 e0
.outp
[ABOVE
] = e1
.outp
[ABOVE
];
1968 e1
.outp
[ABOVE
] = null;
1973 VERTEX(e0
, ABOVE
, LEFT
, ix
, iy
);
1974 e0
.outp
[ABOVE
] = null;
1975 e1
.outp
[ABOVE
] = null;
1979 P_EDGE(prev_edge
, e0
, ABOVE
, px
, iy
);
1980 VERTEX(prev_edge
, ABOVE
, LEFT
, px
, iy
);
1981 N_EDGE(next_edge
, e1
, ABOVE
, nx
, iy
);
1982 VERTEX(next_edge
, ABOVE
, RIGHT
, nx
, iy
);
1983 new_tristrip(&tlist
, prev_edge
, px
, iy
);
1984 e1
.outp
[ABOVE
] = prev_edge
.outp
[ABOVE
];
1985 VERTEX(e1
, ABOVE
, RIGHT
, ix
, iy
);
1986 new_tristrip(&tlist
, e0
, ix
, iy
);
1987 next_edge
.outp
[ABOVE
] = e0
.outp
[ABOVE
];
1988 VERTEX(next_edge
, ABOVE
, RIGHT
, nx
, iy
);
1992 VERTEX(e0
, ABOVE
, LEFT
, ix
, iy
);
1993 N_EDGE(next_edge
, e1
, ABOVE
, nx
, iy
);
1994 VERTEX(next_edge
, ABOVE
, RIGHT
, nx
, iy
);
1995 e1
.outp
[ABOVE
] = e0
.outp
[ABOVE
];
1996 e0
.outp
[ABOVE
] = null;
2001 VERTEX(e1
, ABOVE
, RIGHT
, ix
, iy
);
2002 P_EDGE(prev_edge
, e0
, ABOVE
, px
, iy
);
2003 VERTEX(prev_edge
, ABOVE
, LEFT
, px
, iy
);
2004 e0
.outp
[ABOVE
] = e1
.outp
[ABOVE
];
2005 e1
.outp
[ABOVE
] = null;
2010 VERTEX(e0
, ABOVE
, RIGHT
, ix
, iy
);
2011 VERTEX(e1
, ABOVE
, LEFT
, ix
, iy
);
2012 e0
.outp
[ABOVE
] = null;
2013 e1
.outp
[ABOVE
] = null;
2014 P_EDGE(prev_edge
, e0
, ABOVE
, px
, iy
);
2015 VERTEX(prev_edge
, ABOVE
, LEFT
, px
, iy
);
2016 new_tristrip(&tlist
, prev_edge
, px
, iy
);
2017 N_EDGE(next_edge
, e1
, ABOVE
, nx
, iy
);
2018 VERTEX(next_edge
, ABOVE
, RIGHT
, nx
, iy
);
2019 next_edge
.outp
[ABOVE
] = prev_edge
.outp
[ABOVE
];
2020 VERTEX(next_edge
, ABOVE
, RIGHT
, nx
, iy
);
2025 VERTEX(e0
, ABOVE
, RIGHT
, ix
, iy
);
2026 VERTEX(e1
, ABOVE
, LEFT
, ix
, iy
);
2027 P_EDGE(prev_edge
, e0
, ABOVE
, px
, iy
);
2028 VERTEX(prev_edge
, ABOVE
, LEFT
, px
, iy
);
2029 new_tristrip(&tlist
, prev_edge
, px
, iy
);
2030 N_EDGE(next_edge
, e1
, ABOVE
, nx
, iy
);
2031 VERTEX(next_edge
, ABOVE
, RIGHT
, nx
, iy
);
2032 e1
.outp
[ABOVE
] = prev_edge
.outp
[ABOVE
];
2033 VERTEX(e1
, ABOVE
, RIGHT
, ix
, iy
);
2034 new_tristrip(&tlist
, e0
, ix
, iy
);
2035 next_edge
.outp
[ABOVE
] = e0
.outp
[ABOVE
];
2036 VERTEX(next_edge
, ABOVE
, RIGHT
, nx
, iy
);
2041 VERTEX(e0
, ABOVE
, LEFT
, ix
, iy
);
2042 new_tristrip(&tlist
, e1
, ix
, iy
);
2043 e0
.outp
[ABOVE
]= e1
.outp
[ABOVE
];
2049 } // End of contributing intersection conditional
2051 // Swap bundle sides in response to edge crossing
2052 if (e0
.bundle
[ABOVE
][CLIP
]) e1
.bside
[CLIP
] = !e1
.bside
[CLIP
];
2053 if (e1
.bundle
[ABOVE
][CLIP
]) e0
.bside
[CLIP
] = !e0
.bside
[CLIP
];
2054 if (e0
.bundle
[ABOVE
][SUBJ
]) e1
.bside
[SUBJ
] = !e1
.bside
[SUBJ
];
2055 if (e1
.bundle
[ABOVE
][SUBJ
]) e0
.bside
[SUBJ
] = !e0
.bside
[SUBJ
];
2057 // Swap the edge bundles in the aet
2058 swap_intersecting_edge_bundles(&aet
, intersect
);
2061 // Prepare for next scanbeam
2062 for (edge
= aet
; edge
!is null; edge
= next_edge
) {
2063 next_edge
= edge
.next
;
2064 succ_edge
= edge
.succ
;
2066 if (edge
.top
.y
== yt
&& succ_edge
) {
2067 // Replace AET edge by its successor
2068 succ_edge
.outp
[BELOW
] = edge
.outp
[ABOVE
];
2069 succ_edge
.bstate
[BELOW
] = edge
.bstate
[ABOVE
];
2070 succ_edge
.bundle
[BELOW
][CLIP
] = edge
.bundle
[ABOVE
][CLIP
];
2071 succ_edge
.bundle
[BELOW
][SUBJ
] = edge
.bundle
[ABOVE
][SUBJ
];
2072 prev_edge
= edge
.prev
;
2073 if (prev_edge
) prev_edge
.next
= succ_edge
; else aet
= succ_edge
;
2074 if (next_edge
) next_edge
.prev
= succ_edge
;
2075 succ_edge
.prev
= prev_edge
;
2076 succ_edge
.next
= next_edge
;
2079 edge
.outp
[BELOW
] = edge
.outp
[ABOVE
];
2080 edge
.bstate
[BELOW
] = edge
.bstate
[ABOVE
];
2081 edge
.bundle
[BELOW
][CLIP
] = edge
.bundle
[ABOVE
][CLIP
];
2082 edge
.bundle
[BELOW
][SUBJ
] = edge
.bundle
[ABOVE
][SUBJ
];
2085 edge
.outp
[ABOVE
] = null;
2088 } // === END OF SCANBEAM PROCESSING ==================================
2090 // Generate result tristrip from tlist
2091 result
.strip
= null;
2092 result
.num_strips
= count_tristrips(tlist
);
2093 if (result
.num_strips
> 0) {
2094 result
.strip
= MALLOC
!gpc_vertex_list(result
.num_strips
);
2096 for (tn
= tlist
; tn
!is null; tn
= tnn
) {
2098 if (tn
.active
> 2) {
2099 // Valid tristrip: copy the vertices and free the heap
2100 result
.strip
[s
].num_vertices
= tn
.active
;
2101 result
.strip
[s
].vertex
= MALLOC
!gpc_vertex(tn
.active
);
2103 if (GPC_INVERT_TRISTRIPS
) {
2113 result
.strip
[s
].vertex
[v
].x
= lt
.x
;
2114 result
.strip
[s
].vertex
[v
].y
= lt
.y
;
2121 result
.strip
[s
].vertex
[v
].x
= rt
.x
;
2122 result
.strip
[s
].vertex
[v
].y
= rt
.y
;
2130 // Invalid tristrip: just free the heap
2131 for (lt
= tn
.v
[LEFT
]; lt
!is null; lt
= ltn
) {
2135 for (rt
= tn
.v
[RIGHT
]; rt
!is null; rt
= rtn
) {