44import java .util .List ;
55import java .util .logging .Logger ;
66
7+ import de .lighti .clipper .Path .OutRec ;
78import de .lighti .clipper .Point .LongPoint ;
89
910public abstract class ClipperBase implements Clipper {
@@ -12,12 +13,18 @@ protected class LocalMinima {
1213 Edge leftBound ;
1314 Edge rightBound ;
1415 LocalMinima next ;
15- };
16+ }
1617
1718 protected class Scanbeam {
1819 long y ;
1920 Scanbeam next ;
20- };
21+ }
22+
23+ protected class Maxima {
24+ long x ;
25+ Maxima next ;
26+ Maxima prev ;
27+ }
2128
2229 private static void initEdge ( Edge e , Edge eNext , Edge ePrev , LongPoint pt ) {
2330 e .next = eNext ;
@@ -65,7 +72,13 @@ private static Edge removeEdge( Edge e ) {
6572
6673 protected LocalMinima currentLM ;
6774
68- private final List <List <Edge >> edges ;
75+ private final List <List <Edge >> edges = new ArrayList <List <Edge >>();
76+
77+ protected Scanbeam scanbeam ;
78+
79+ protected final List <OutRec > polyOuts = new ArrayList <OutRec >();
80+
81+ protected Edge activeEdges ;
6982
7083 protected boolean hasOpenPaths ;
7184
@@ -79,7 +92,6 @@ protected ClipperBase( boolean preserveCollinear ) //constructor (nb: no externa
7992 minimaList = null ;
8093 currentLM = null ;
8194 hasOpenPaths = false ;
82- edges = new ArrayList <List <Edge >>();
8395 }
8496
8597 @ Override
@@ -189,21 +201,19 @@ else if (Closed && Point.slopesEqual( e.prev.getCurrent(), e.getCurrent(), e.nex
189201 return false ;
190202 }
191203 e .prev .outIdx = Edge .SKIP ;
192- if (e .prev .getBot ().getX () < e .prev .getTop ().getX ()) {
193- e .prev .reverseHorizontal ();
194- }
195204 final LocalMinima locMin = new LocalMinima ();
196205 locMin .next = null ;
197206 locMin .y = e .getBot ().getY ();
198207 locMin .leftBound = null ;
199208 locMin .rightBound = e ;
200209 locMin .rightBound .side = Edge .Side .RIGHT ;
201210 locMin .rightBound .windDelta = 0 ;
202- while (e .next .outIdx != Edge .SKIP ) {
203- e .nextInLML = e .next ;
211+ for ( ; ; ) {
204212 if (e .getBot ().getX () != e .prev .getTop ().getX ()) {
205213 e .reverseHorizontal ();
206214 }
215+ if (e .next .outIdx == Edge .SKIP ) break ;
216+ e .nextInLML = e .next ;
207217 e = e .next ;
208218 }
209219 insertLocalMinima ( locMin );
@@ -333,12 +343,14 @@ public boolean isPreserveCollinear() {
333343 return preserveCollinear ;
334344 }
335345
336- protected void popLocalMinima () {
346+ protected boolean popLocalMinima ( long y , LocalMinima [] current ) {
337347 LOGGER .entering ( ClipperBase .class .getName (), "popLocalMinima" );
338- if (currentLM == null ) {
339- return ;
348+ current [0 ] = currentLM ;
349+ if (currentLM != null && currentLM .y == y ) {
350+ currentLM = currentLM .next ;
351+ return true ;
340352 }
341- currentLM = currentLM . next ;
353+ return false ;
342354 }
343355
344356 private Edge processBound ( Edge e , boolean LeftBoundIsForward ) {
@@ -403,17 +415,15 @@ private Edge processBound( Edge e, boolean LeftBoundIsForward ) {
403415 else {
404416 EStart = e .next ;
405417 }
406- if (EStart .outIdx != Edge .SKIP ) {
407- if (EStart .deltaX == Edge .HORIZONTAL ) //ie an adjoining horizontal skip edge
408- {
409- if (EStart .getBot ().getX () != e .getBot ().getX () && EStart .getTop ().getX () != e .getBot ().getX ()) {
410- e .reverseHorizontal ();
411- }
412- }
413- else if (EStart .getBot ().getX () != e .getBot ().getX ()) {
418+ if (EStart .deltaX == Edge .HORIZONTAL ) //ie an adjoining horizontal skip edge
419+ {
420+ if (EStart .getBot ().getX () != e .getBot ().getX () && EStart .getTop ().getX () != e .getBot ().getX ()) {
414421 e .reverseHorizontal ();
415422 }
416423 }
424+ else if (EStart .getBot ().getX () != e .getBot ().getX ()) {
425+ e .reverseHorizontal ();
426+ }
417427 }
418428
419429 EStart = e ;
@@ -429,12 +439,7 @@ else if (EStart.getBot().getX() != e.getBot().getX()) {
429439 while (Horz .prev .deltaX == Edge .HORIZONTAL ) {
430440 Horz = Horz .prev ;
431441 }
432- if (Horz .prev .getTop ().getX () == result .next .getTop ().getX ()) {
433- if (!LeftBoundIsForward ) {
434- result = Horz .prev ;
435- }
436- }
437- else if (Horz .prev .getTop ().getX () > result .next .getTop ().getX ()) {
442+ if (Horz .prev .getTop ().getX () > result .next .getTop ().getX ()) {
438443 result = Horz .prev ;
439444 }
440445 }
@@ -459,13 +464,9 @@ else if (Horz.prev.getTop().getX() > result.next.getTop().getX()) {
459464 while (Horz .next .deltaX == Edge .HORIZONTAL ) {
460465 Horz = Horz .next ;
461466 }
462- if (Horz .next .getTop ().getX () == result .prev .getTop ().getX ()) {
463- if (! LeftBoundIsForward ) {
467+ if (Horz .next .getTop ().getX () == result .prev .getTop ().getX () ||
468+ Horz . next . getTop (). getX () > result . prev . getTop (). getX () ) {
464469 result = Horz .next ;
465- }
466- }
467- else if (Horz .next .getTop ().getX () > result .prev .getTop ().getX ()) {
468- result = Horz .next ;
469470 }
470471 }
471472
@@ -491,22 +492,206 @@ protected void reset() {
491492 }
492493
493494 //reset all edges ...
495+ scanbeam = null ;
494496 LocalMinima lm = minimaList ;
495497 while (lm != null ) {
498+ insertScanbeam (lm .y );
496499 Edge e = lm .leftBound ;
497500 if (e != null ) {
498501 e .setCurrent ( new LongPoint ( e .getBot () ) );
499- e .side = Edge .Side .LEFT ;
500502 e .outIdx = Edge .UNASSIGNED ;
501503 }
502504 e = lm .rightBound ;
503505 if (e != null ) {
504506 e .setCurrent ( new LongPoint ( e .getBot () ) );
505- e .side = Edge .Side .RIGHT ;
506507 e .outIdx = Edge .UNASSIGNED ;
507508 }
508509 lm = lm .next ;
509510 }
511+ activeEdges = null ;
512+ }
513+
514+ protected void insertScanbeam ( long y ) {
515+ LOGGER .entering ( ClipperBase .class .getName (), "insertScanbeam" );
516+
517+ //single-linked list: sorted descending, ignoring dups.
518+ if (scanbeam == null ) {
519+ scanbeam = new Scanbeam ();
520+ scanbeam .next = null ;
521+ scanbeam .y = y ;
522+ }
523+ else if (y > scanbeam .y ) {
524+ final Scanbeam newSb = new Scanbeam ();
525+ newSb .y = y ;
526+ newSb .next = scanbeam ;
527+ scanbeam = newSb ;
528+ }
529+ else {
530+ Scanbeam sb2 = scanbeam ;
531+ while (sb2 .next != null && (y <= sb2 .next .y )) {
532+ sb2 = sb2 .next ;
533+ }
534+ if (y == sb2 .y ) {
535+ return ; //ie ignores duplicates
536+ }
537+ final Scanbeam newSb = new Scanbeam ();
538+ newSb .y = y ;
539+ newSb .next = sb2 .next ;
540+ sb2 .next = newSb ;
541+ }
510542 }
511543
544+ protected boolean popScanbeam ( long [] y ) {
545+ if (scanbeam == null ) {
546+ y [0 ] = 0 ;
547+ return false ;
548+ }
549+ y [0 ] = scanbeam .y ;
550+ scanbeam = scanbeam .next ;
551+ return true ;
552+ }
553+
554+ protected final boolean localMinimaPending () {
555+ return currentLM != null ;
556+ }
557+
558+ protected OutRec createOutRec () {
559+ OutRec result = new OutRec ();
560+ result .Idx = Edge .UNASSIGNED ;
561+ result .isHole = false ;
562+ result .isOpen = false ;
563+ result .firstLeft = null ;
564+ result .setPoints ( null );
565+ result .bottomPt = null ;
566+ result .polyNode = null ;
567+ polyOuts .add ( result );
568+ result .Idx = polyOuts .size () - 1 ;
569+ return result ;
570+ }
571+
572+ protected void disposeOutRec ( int index ) {
573+ OutRec outRec = polyOuts .get ( index );
574+ outRec .setPoints ( null );
575+ outRec = null ;
576+ polyOuts .set ( index , null );
577+ }
578+
579+ protected void updateEdgeIntoAEL ( Edge e ) {
580+ if (e .nextInLML == null ) {
581+ throw new IllegalStateException ("UpdateEdgeIntoAEL: invalid call" );
582+ }
583+ final Edge aelPrev = e .prevInAEL ;
584+ final Edge aelNext = e .nextInAEL ;
585+ e .nextInLML .outIdx = e .outIdx ;
586+ if (aelPrev != null ) {
587+ aelPrev .nextInAEL = e .nextInLML ;
588+ }
589+ else {
590+ activeEdges = e .nextInLML ;
591+ }
592+ if (aelNext != null ) {
593+ aelNext .prevInAEL = e .nextInLML ;
594+ }
595+ e .nextInLML .side = e .side ;
596+ e .nextInLML .windDelta = e .windDelta ;
597+ e .nextInLML .windCnt = e .windCnt ;
598+ e .nextInLML .windCnt2 = e .windCnt2 ;
599+ e = e .nextInLML ;
600+ e .setCurrent (e .getBot ());
601+ e .prevInAEL = aelPrev ;
602+ e .nextInAEL = aelNext ;
603+ if (e .isHorizontal ()) {
604+ insertScanbeam (e .getTop ().getY ());
605+ }
606+ }
607+
608+ protected void swapPositionsInAEL ( Edge edge1 , Edge edge2 ) {
609+ LOGGER .entering ( ClipperBase .class .getName (), "swapPositionsInAEL" );
610+
611+ //check that one or other edge hasn't already been removed from AEL ...
612+ if (edge1 .nextInAEL == edge1 .prevInAEL || edge2 .nextInAEL == edge2 .prevInAEL ) {
613+ return ;
614+ }
615+
616+ if (edge1 .nextInAEL == edge2 ) {
617+ final Edge next = edge2 .nextInAEL ;
618+ if (next != null ) {
619+ next .prevInAEL = edge1 ;
620+ }
621+ final Edge prev = edge1 .prevInAEL ;
622+ if (prev != null ) {
623+ prev .nextInAEL = edge2 ;
624+ }
625+ edge2 .prevInAEL = prev ;
626+ edge2 .nextInAEL = edge1 ;
627+ edge1 .prevInAEL = edge2 ;
628+ edge1 .nextInAEL = next ;
629+ }
630+ else if (edge2 .nextInAEL == edge1 ) {
631+ final Edge next = edge1 .nextInAEL ;
632+ if (next != null ) {
633+ next .prevInAEL = edge2 ;
634+ }
635+ final Edge prev = edge2 .prevInAEL ;
636+ if (prev != null ) {
637+ prev .nextInAEL = edge1 ;
638+ }
639+ edge1 .prevInAEL = prev ;
640+ edge1 .nextInAEL = edge2 ;
641+ edge2 .prevInAEL = edge1 ;
642+ edge2 .nextInAEL = next ;
643+ }
644+ else {
645+ final Edge next = edge1 .nextInAEL ;
646+ final Edge prev = edge1 .prevInAEL ;
647+ edge1 .nextInAEL = edge2 .nextInAEL ;
648+ if (edge1 .nextInAEL != null ) {
649+ edge1 .nextInAEL .prevInAEL = edge1 ;
650+ }
651+ edge1 .prevInAEL = edge2 .prevInAEL ;
652+ if (edge1 .prevInAEL != null ) {
653+ edge1 .prevInAEL .nextInAEL = edge1 ;
654+ }
655+ edge2 .nextInAEL = next ;
656+ if (edge2 .nextInAEL != null ) {
657+ edge2 .nextInAEL .prevInAEL = edge2 ;
658+ }
659+ edge2 .prevInAEL = prev ;
660+ if (edge2 .prevInAEL != null ) {
661+ edge2 .prevInAEL .nextInAEL = edge2 ;
662+ }
663+ }
664+
665+ if (edge1 .prevInAEL == null ) {
666+ activeEdges = edge1 ;
667+ }
668+ else if (edge2 .prevInAEL == null ) {
669+ activeEdges = edge2 ;
670+ }
671+
672+ LOGGER .exiting ( ClipperBase .class .getName (), "swapPositionsInAEL" );
673+ }
674+
675+ protected void deleteFromAEL ( Edge e ) {
676+ LOGGER .entering ( ClipperBase .class .getName (), "deleteFromAEL" );
677+
678+ Edge aelPrev = e .prevInAEL ;
679+ Edge aelNext = e .nextInAEL ;
680+ if (aelPrev == null && aelNext == null && (e != activeEdges )) {
681+ return ; //already deleted
682+ }
683+ if (aelPrev != null ) {
684+ aelPrev .nextInAEL = aelNext ;
685+ }
686+ else {
687+ activeEdges = aelNext ;
688+ }
689+ if (aelNext != null ) {
690+ aelNext .prevInAEL = aelPrev ;
691+ }
692+ e .nextInAEL = null ;
693+ e .prevInAEL = null ;
694+
695+ LOGGER .exiting ( ClipperBase .class .getName (), "deleteFromAEL" );
696+ }
512697}
0 commit comments