@@ -1561,7 +1561,7 @@ else if (pt.opEquals(ae1.localMin.vertex.pt) && !IsOpenEnd(ae1.localMin.vertex))
15611561 resultOp = AddLocalMaxPoly (ae1 , ae2 , pt );
15621562 } else if (IsFront (ae1 ) || (ae1 .outrec == ae2 .outrec )) {
15631563 // this 'else if' condition isn't strictly needed but
1564- // it's sensible to split polygons that ony touch at
1564+ // it's sensible to split polygons that only touch at
15651565 // a common vertex (not at common edges).
15661566 resultOp = AddLocalMaxPoly (ae1 , ae2 , pt );
15671567 AddLocalMinPoly (ae1 , ae2 , pt );
@@ -1659,11 +1659,9 @@ private void AdjustCurrXAndCopyToSEL(long topY) {
16591659 ae .prevInSEL = ae .prevInAEL ;
16601660 ae .nextInSEL = ae .nextInAEL ;
16611661 ae .jump = ae .nextInSEL ;
1662- if (ae .joinWith == JoinWith .Left ) {
1663- ae .curX = ae .prevInAEL .curX ; // this also avoids complications
1664- } else {
1665- ae .curX = TopX (ae , topY );
1666- }
1662+ // it's safe to ignore joined edges here because
1663+ // if necessary they get split in IntersectEdges()
1664+ ae .curX = TopX (ae , topY );
16671665 // NB don't update ae.curr.y yet (see AddNewIntersectNode)
16681666 ae = ae .nextInAEL ;
16691667 }
@@ -2480,7 +2478,7 @@ private static PointInPolygonResult PointInOpPolygon(Point64 pt, OutPt op) {
24802478 break ;
24812479 }
24822480
2483- // must have touched or crossed the pt.y horizonal
2481+ // must have touched or crossed the pt.y horizontal
24842482 // and this must happen an even number of times
24852483
24862484 if (op2 .pt .y == pt .y ) // touching the horizontal
@@ -2532,25 +2530,29 @@ private static PointInPolygonResult PointInOpPolygon(Point64 pt, OutPt op) {
25322530 private static boolean Path1InsidePath2 (OutPt op1 , OutPt op2 ) {
25332531 // we need to make some accommodation for rounding errors
25342532 // so we won't jump if the first vertex is found outside
2535- PointInPolygonResult result ;
2536- int outsideCnt = 0 ;
2533+ PointInPolygonResult pip = PointInPolygonResult .IsOn ;
25372534 OutPt op = op1 ;
25382535 do {
2539- result = PointInOpPolygon (op .pt , op2 );
2540- if (result == PointInPolygonResult .IsOutside ) {
2541- ++outsideCnt ;
2542- } else if (result == PointInPolygonResult .IsInside ) {
2543- --outsideCnt ;
2536+ switch (PointInOpPolygon (op .pt , op2 )) {
2537+ case IsOutside :
2538+ if (pip == PointInPolygonResult .IsOutside ) {
2539+ return false ;
2540+ }
2541+ pip = PointInPolygonResult .IsOutside ;
2542+ break ;
2543+ case IsInside :
2544+ if (pip == PointInPolygonResult .IsInside ) {
2545+ return true ;
2546+ }
2547+ pip = PointInPolygonResult .IsInside ;
2548+ break ;
2549+ default :
2550+ break ;
25442551 }
25452552 op = op .next ;
2546- } while (op != op1 && Math .abs (outsideCnt ) < 2 );
2547- if (Math .abs (outsideCnt ) > 1 ) {
2548- return (outsideCnt < 0 );
2549- }
2550- // since path1's location is still equivocal, check its midpoint
2551- Point64 mp = GetBounds (GetCleanPath (op1 )).MidPoint ();
2552- Path64 path2 = GetCleanPath (op2 );
2553- return InternalClipper .PointInPolygon (mp , path2 ) != PointInPolygonResult .IsOutside ;
2553+ } while (op != op1 );
2554+ // result is unclear, so try again using cleaned paths
2555+ return InternalClipper .Path2ContainsPath1 (GetCleanPath (op1 ), GetCleanPath (op2 )); // #973
25542556 }
25552557
25562558 private void MoveSplits (OutRec fromOr , OutRec toOr ) {
@@ -2771,9 +2773,8 @@ private void FixSelfIntersects(OutRec outrec) {
27712773 }
27722774 op2 = outrec .pts ;
27732775 continue ;
2774- } else {
2775- op2 = op2 .next ;
27762776 }
2777+ op2 = op2 .next ;
27772778 if (op2 == outrec .pts ) {
27782779 break ;
27792780 }
@@ -2849,28 +2850,6 @@ protected final boolean BuildPaths(Paths64 solutionClosed, Paths64 solutionOpen)
28492850 return true ;
28502851 }
28512852
2852- public static Rect64 GetBounds (Path64 path ) {
2853- if (path .isEmpty ()) {
2854- return new Rect64 ();
2855- }
2856- Rect64 result = Clipper .InvalidRect64 .clone ();
2857- for (Point64 pt : path ) {
2858- if (pt .x < result .left ) {
2859- result .left = pt .x ;
2860- }
2861- if (pt .x > result .right ) {
2862- result .right = pt .x ;
2863- }
2864- if (pt .y < result .top ) {
2865- result .top = pt .y ;
2866- }
2867- if (pt .y > result .bottom ) {
2868- result .bottom = pt .y ;
2869- }
2870- }
2871- return result ;
2872- }
2873-
28742853 private boolean CheckBounds (OutRec outrec ) {
28752854 if (outrec .pts == null ) {
28762855 return false ;
@@ -2882,27 +2861,33 @@ private boolean CheckBounds(OutRec outrec) {
28822861 if (outrec .pts == null || !BuildPath (outrec .pts , getReverseSolution (), false , outrec .path )) {
28832862 return false ;
28842863 }
2885- outrec .bounds = GetBounds (outrec .path );
2864+ outrec .bounds = InternalClipper . GetBounds (outrec .path );
28862865 return true ;
28872866 }
28882867
28892868 private boolean CheckSplitOwner (OutRec outrec , List <Integer > splits ) {
2890- if (outrec .owner == null || outrec .owner .splits == null ) {
2891- return false ;
2892- }
28932869 for (int i : splits ) {
2894- OutRec split = GetRealOutRec (outrecList .get (i ));
2870+ OutRec split = outrecList .get (i );
2871+ if (split .pts == null && split .splits != null && CheckSplitOwner (outrec , split .splits )) {
2872+ return true ; // #942
2873+ }
2874+ split = GetRealOutRec (split );
28952875 if (split == null || split == outrec || split .recursiveSplit == outrec ) {
28962876 continue ;
28972877 }
28982878 split .recursiveSplit = outrec ; // #599
28992879 if (split .splits != null && CheckSplitOwner (outrec , split .splits )) {
29002880 return true ;
29012881 }
2902- if (IsValidOwner (outrec , split ) && CheckBounds (split ) && split .bounds .Contains (outrec .bounds ) && Path1InsidePath2 (outrec .pts , split .pts )) {
2903- outrec .owner = split ; // found in split
2904- return true ;
2882+ if (!CheckBounds (split ) || !split .bounds .Contains (outrec .bounds ) || !Path1InsidePath2 (outrec .pts , split .pts )) {
2883+ continue ;
2884+ }
2885+ if (!IsValidOwner (outrec , split )) {
2886+ // split is owned by outrec (#957)
2887+ split .owner = outrec .owner ;
29052888 }
2889+ outrec .owner = split ; // found in split
2890+ return true ;
29062891 }
29072892 return false ;
29082893 }
0 commit comments