Skip to content
This repository was archived by the owner on Dec 28, 2024. It is now read-only.

Commit d3057a0

Browse files
author
Tobias Mahlmann
authored
Merge pull request #5 from marle/master
Applied changes from C# version of Clipper 6.4.2 and fixed some NPE exceptions.
2 parents bc784fc + 11c10fc commit d3057a0

5 files changed

Lines changed: 587 additions & 410 deletions

File tree

Clipper/src/de/lighti/clipper/ClipperBase.java

Lines changed: 220 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.util.List;
55
import java.util.logging.Logger;
66

7+
import de.lighti.clipper.Path.OutRec;
78
import de.lighti.clipper.Point.LongPoint;
89

910
public 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

Comments
 (0)