diff --git a/src/main/java/clipper2/engine/ClipperBase.java b/src/main/java/clipper2/engine/ClipperBase.java index 2910965..22c0d93 100644 --- a/src/main/java/clipper2/engine/ClipperBase.java +++ b/src/main/java/clipper2/engine/ClipperBase.java @@ -17,8 +17,6 @@ import clipper2.core.Paths64; import clipper2.core.Point64; import clipper2.core.Rect64; -import tangible.OutObject; -import tangible.RefObject; /** * Subject and Clip paths are passed to a Clipper object via AddSubject, @@ -455,12 +453,6 @@ private static boolean IsHeadingLeftHorz(Active ae) { return Double.POSITIVE_INFINITY == ae.dx; } - private static void SwapActives(RefObject ae1, RefObject ae2) { - Active temp = ae1.argValue; - ae1.argValue = ae2.argValue; - ae2.argValue = temp; - } - private static PathType GetPolyType(Active ae) { return ae.localMin.polytype; } @@ -1097,26 +1089,20 @@ private void InsertLocalMinimaIntoAEL(long botY) { if (leftBound != null && rightBound != null) { if (IsHorizontal(leftBound)) { if (IsHeadingRightHorz(leftBound)) { - RefObject tempRefleftBound = new RefObject<>(leftBound); - RefObject tempRefrightBound = new RefObject<>(rightBound); - SwapActives(tempRefleftBound, tempRefrightBound); - rightBound = tempRefrightBound.argValue; - leftBound = tempRefleftBound.argValue; + Active tmp = leftBound; + leftBound = rightBound; + rightBound = tmp; } } else if (IsHorizontal(rightBound)) { if (IsHeadingLeftHorz(rightBound)) { - RefObject tempRefleftBound2 = new RefObject<>(leftBound); - RefObject tempRefrightBound2 = new RefObject<>(rightBound); - SwapActives(tempRefleftBound2, tempRefrightBound2); - rightBound = tempRefrightBound2.argValue; - leftBound = tempRefleftBound2.argValue; + Active tmp = leftBound; + leftBound = rightBound; + rightBound = tmp; } } else if (leftBound.dx < rightBound.dx) { - RefObject tempRefleftBound3 = new RefObject<>(leftBound); - RefObject tempRefrightBound3 = new RefObject<>(rightBound); - SwapActives(tempRefleftBound3, tempRefrightBound3); - rightBound = tempRefrightBound3.argValue; - leftBound = tempRefleftBound3.argValue; + Active tmp = leftBound; + leftBound = rightBound; + rightBound = tmp; } // so when leftBound has windDx == 1, the polygon will be oriented // counter-clockwise in Cartesian coords (clockwise with inverted y). @@ -1177,13 +1163,12 @@ private void PushHorz(Active ae) { sel = ae; } - private boolean PopHorz(OutObject ae) { - ae.argValue = sel; - if (sel == null) { - return false; + private @Nullable Active PopHorz() { + Active ae = sel; + if (ae != null) { + sel = sel.nextInSEL; } - sel = sel.nextInSEL; - return true; + return ae; } private OutPt AddLocalMinPoly(Active ae1, Active ae2, Point64 pt) { @@ -1441,11 +1426,9 @@ private OutPt IntersectEdges(Active ae1, Active ae2, Point64 pt) { } // the following line avoids duplicating quite a bit of code if (IsOpen(ae2)) { - RefObject tempRefae1 = new RefObject<>(ae1); - RefObject tempRefae2 = new RefObject<>(ae2); - SwapActives(tempRefae1, tempRefae2); - ae2 = tempRefae2.argValue; - ae1 = tempRefae1.argValue; + Active temp = ae1; + ae1 = ae2; + ae2 = temp; } if (IsJoined(ae2)) { Split(ae2, pt); // needed for safety @@ -1706,10 +1689,8 @@ protected final void ExecuteInternal(ClipType ct, FillRule fillRule) { long y = scanlineSet.pollLast(); while (succeeded) { InsertLocalMinimaIntoAEL(y); - Active ae = null; - OutObject tempOutae = new OutObject<>(); - while (PopHorz(tempOutae)) { - ae = tempOutae.argValue; + Active ae; + while ((ae = PopHorz()) != null) { DoHorizontal(ae); } if (!horzSegList.isEmpty()) { @@ -1723,9 +1704,7 @@ protected final void ExecuteInternal(ClipType ct, FillRule fillRule) { y = scanlineSet.pollLast(); DoIntersections(y); DoTopOfScanbeam(y); - OutObject tempOutae2 = new OutObject<>(); - while (PopHorz(tempOutae2)) { - ae = tempOutae2.argValue; + while ((ae = PopHorz()) != null) { DoHorizontal(ae); } } @@ -1921,26 +1900,34 @@ private void SwapPositionsInAEL(Active ae1, Active ae2) { } } - private static boolean ResetHorzDirection(Active horz, @Nullable Vertex vertexMax, OutObject leftX, OutObject rightX) { + private static final class HorzDirection { + final boolean leftToRight; + final long leftX; + final long rightX; + + HorzDirection(boolean leftToRight, long leftX, long rightX) { + this.leftToRight = leftToRight; + this.leftX = leftX; + this.rightX = rightX; + } + } + + private static HorzDirection ResetHorzDirection(Active horz, @Nullable Vertex vertexMax) { if (horz.bot.x == horz.top.x) { // the horizontal edge is going nowhere ... - leftX.argValue = horz.curX; - rightX.argValue = horz.curX; + long leftX = horz.curX; + long rightX = horz.curX; Active ae = horz.nextInAEL; while (ae != null && ae.vertexTop != vertexMax) { ae = ae.nextInAEL; } - return ae != null; + return new HorzDirection(ae != null, leftX, rightX); } if (horz.curX < horz.top.x) { - leftX.argValue = horz.curX; - rightX.argValue = horz.top.x; - return true; + return new HorzDirection(true, horz.curX, horz.top.x); } - leftX.argValue = horz.top.x; - rightX.argValue = horz.curX; - return false; // right to left + return new HorzDirection(false, horz.top.x, horz.curX); // right to left } private void TrimHorz(Active horzEdge, boolean preserveCollinear) { @@ -2002,13 +1989,10 @@ private void DoHorizontal(Active horz) @Nullable Vertex vertexMax = horzIsOpen ? GetCurrYMaximaVertex_Open(horz) : GetCurrYMaximaVertex(horz); - long leftX; - OutObject tempOutleftX = new OutObject<>(); - long rightX; - OutObject tempOutrightX = new OutObject<>(); - boolean isLeftToRight = ResetHorzDirection(horz, vertexMax, tempOutleftX, tempOutrightX); - rightX = tempOutrightX.argValue; - leftX = tempOutleftX.argValue; + HorzDirection direction = ResetHorzDirection(horz, vertexMax); + boolean isLeftToRight = direction.leftToRight; + long rightX = direction.rightX; + long leftX = direction.leftX; if (IsHotEdge(horz)) { OutPt op = AddOutPt(horz, new Point64(horz.curX, Y)); @@ -2120,11 +2104,10 @@ else if ((isLeftToRight && (TopX(ae, pt.y) >= pt.x)) || (!isLeftToRight && (TopX UpdateEdgeIntoAEL(horz); - OutObject tempOutleftX2 = new OutObject<>(); - OutObject tempOutrightX2 = new OutObject<>(); - isLeftToRight = ResetHorzDirection(horz, vertexMax, tempOutleftX2, tempOutrightX2); - rightX = tempOutrightX2.argValue; - leftX = tempOutleftX2.argValue; + direction = ResetHorzDirection(horz, vertexMax); + isLeftToRight = direction.leftToRight; + rightX = direction.rightX; + leftX = direction.leftX; } // end for loop and end of (possible consecutive) horizontals diff --git a/src/main/java/clipper2/offset/ClipperOffset.java b/src/main/java/clipper2/offset/ClipperOffset.java index 3e94086..858e929 100644 --- a/src/main/java/clipper2/offset/ClipperOffset.java +++ b/src/main/java/clipper2/offset/ClipperOffset.java @@ -19,7 +19,6 @@ import clipper2.core.Rect64; import clipper2.engine.Clipper64; import clipper2.engine.PolyTree64; -import tangible.RefObject; /** * Manages the process of offsetting (inflating/deflating) both open and closed @@ -505,14 +504,14 @@ private void BuildNormals(Path64 path) { normals.add(GetUnitNormal(path.get(cnt - 1), path.get(0))); } - private void OffsetPoint(Group group, Path64 path, int j, RefObject k) { + private int OffsetPoint(Group group, Path64 path, int j, int k) { // Let A = change in angle where edges join // A == 0: ie no change in angle (flat join) // A == PI: edges 'spike' // sin(A) < 0: right turning // cos(A) < 0: change in angle is more than 90 degree - double sinA = InternalClipper.CrossProduct(normals.get(j), normals.get(k.argValue)); - double cosA = InternalClipper.DotProduct(normals.get(j), normals.get(k.argValue)); + double sinA = InternalClipper.CrossProduct(normals.get(j), normals.get(k)); + double cosA = InternalClipper.DotProduct(normals.get(j), normals.get(k)); if (sinA > 1.0) { sinA = 1.0; } else if (sinA < -1.0) { @@ -520,50 +519,50 @@ private void OffsetPoint(Group group, Path64 path, int j, RefObject k) } if (deltaCallback != null) { - groupDelta = deltaCallback.calculate(path, normals, j, k.argValue); + groupDelta = deltaCallback.calculate(path, normals, j, k); if (group.pathsReversed) { groupDelta = -groupDelta; } } if (Math.abs(groupDelta) < TOLERANCE) { pathOut.add(path.get(j)); - return; + return j; } if (cosA > -0.99 && (sinA * groupDelta < 0)) { // test for concavity first (#593) // is concave - pathOut.add(GetPerpendic(path.get(j), normals.get(k.argValue))); + pathOut.add(GetPerpendic(path.get(j), normals.get(k))); // this extra point is the only (simple) way to ensure that // path reversals are fully cleaned with the trailing clipper pathOut.add(path.get(j)); // (#405) pathOut.add(GetPerpendic(path.get(j), normals.get(j))); } else if (cosA > 0.999 && joinType != JoinType.Round) { // almost straight - less than 2.5 degree (#424, #482, #526 & #724) - DoMiter(group, path, j, k.argValue, cosA); + DoMiter(group, path, j, k, cosA); } else if (joinType == JoinType.Miter) { // miter unless the angle is sufficiently acute to exceed ML if (cosA > mitLimSqr - 1) { - DoMiter(group, path, j, k.argValue, cosA); + DoMiter(group, path, j, k, cosA); } else { - DoSquare(path, j, k.argValue); + DoSquare(path, j, k); } } else if (joinType == JoinType.Round) { - DoRound(path, j, k.argValue, Math.atan2(sinA, cosA)); + DoRound(path, j, k, Math.atan2(sinA, cosA)); } else if (joinType == JoinType.Bevel) { - DoBevel(path, j, k.argValue); + DoBevel(path, j, k); } else { - DoSquare(path, j, k.argValue); + DoSquare(path, j, k); } - k.argValue = j; + return j; } private void OffsetPolygon(Group group, Path64 path) { pathOut = new Path64(); int cnt = path.size(); - RefObject prev = new RefObject(cnt - 1); + int prev = cnt - 1; for (int i = 0; i < cnt; i++) { - OffsetPoint(group, path, i, prev); + prev = OffsetPoint(group, path, i, prev); } solution.add(pathOut); } @@ -617,9 +616,9 @@ private void OffsetOpenPath(Group group, Path64 path) { } // offset the left side going forward - RefObject kRef = new RefObject<>(0); + int k = 0; for (int i = 1; i < highI; i++) { - OffsetPoint(group, path, i, kRef); + k = OffsetPoint(group, path, i, k); } // reverse normals ... @@ -650,9 +649,9 @@ private void OffsetOpenPath(Group group, Path64 path) { } // offset the left side going back - kRef.argValue = highI; // Initialize k to the last point index + k = highI; // Initialize k to the last point index for (int i = highI - 1; i > 0; i--) { - OffsetPoint(group, path, i, kRef); + k = OffsetPoint(group, path, i, k); } // Add the final point on the reversed side pathOut.add(GetPerpendic(path.get(0), normals.get(1))); @@ -763,4 +762,4 @@ private static boolean ValidateBounds(List boundsList, double delta) { return true; } -} \ No newline at end of file +} diff --git a/src/main/java/clipper2/rectclip/RectClip64.java b/src/main/java/clipper2/rectclip/RectClip64.java index b67ca66..927dfbf 100644 --- a/src/main/java/clipper2/rectclip/RectClip64.java +++ b/src/main/java/clipper2/rectclip/RectClip64.java @@ -10,7 +10,6 @@ import clipper2.core.Point64; import clipper2.core.Rect64; import clipper2.engine.PointInPolygonResult; -import tangible.RefObject; /** * RectClip64 intersects subject polygons with the specified rectangular @@ -30,6 +29,36 @@ protected enum Location { left, top, right, bottom, inside } + protected static final class LocationResult { + final boolean outside; + final Location location; + + LocationResult(boolean outside, Location location) { + this.outside = outside; + this.location = location; + } + } + + protected static final class IntersectionResult { + final boolean intersects; + final Location location; + + IntersectionResult(boolean intersects, Location location) { + this.intersects = intersects; + this.location = location; + } + } + + protected static final class NextLocationResult { + final Location location; + final int index; + + NextLocationResult(Location location, int index) { + this.location = location; + this.index = index; + } + } + protected final Rect64 rect_; protected final Point64 mp_; protected final Path64 rectPath_; @@ -208,33 +237,30 @@ private void addCorner(Location prev, Location curr) { add(headingClockwise(prev, curr) ? rectPath_.get(prev.ordinal()) : rectPath_.get(curr.ordinal())); } - private void addCorner(RefObject locRefObject, boolean cw) { + private Location addCorner(Location loc, boolean cw) { if (cw) { - add(rectPath_.get(locRefObject.argValue.ordinal())); - locRefObject.argValue = getAdjacentLocation(locRefObject.argValue, true); + add(rectPath_.get(loc.ordinal())); + return getAdjacentLocation(loc, true); } else { - locRefObject.argValue = getAdjacentLocation(locRefObject.argValue, false); - add(rectPath_.get(locRefObject.argValue.ordinal())); + Location nextLoc = getAdjacentLocation(loc, false); + add(rectPath_.get(nextLoc.ordinal())); + return nextLoc; } } - protected static boolean getLocation(Rect64 r, Point64 pt, RefObject locRefObject) { + protected static LocationResult getLocation(Rect64 r, Point64 pt) { Location loc; if (pt.x == r.left && pt.y >= r.top && pt.y <= r.bottom) { - locRefObject.argValue = Location.left; - return false; + return new LocationResult(false, Location.left); } if (pt.x == r.right && pt.y >= r.top && pt.y <= r.bottom) { - locRefObject.argValue = Location.right; - return false; + return new LocationResult(false, Location.right); } if (pt.y == r.top && pt.x >= r.left && pt.x <= r.right) { - locRefObject.argValue = Location.top; - return false; + return new LocationResult(false, Location.top); } if (pt.y == r.bottom && pt.x >= r.left && pt.x <= r.right) { - locRefObject.argValue = Location.bottom; - return false; + return new LocationResult(false, Location.bottom); } if (pt.x < r.left) { loc = Location.left; @@ -247,8 +273,7 @@ protected static boolean getLocation(Rect64 r, Point64 pt, RefObject l } else { loc = Location.inside; } - locRefObject.argValue = loc; - return true; + return new LocationResult(true, loc); } private static boolean isHorizontal(Point64 a, Point64 b) { @@ -314,85 +339,71 @@ private static boolean getSegmentIntersection(Point64 p1, Point64 p2, Point64 p3 return InternalClipper.GetIntersectPoint(p1, p2, p3, p4, ipRefObject); } - protected static boolean getIntersection(Path64 rectPath, Point64 p, Point64 p2, RefObject locRefObject, Point64 ipRefObject) { + protected static IntersectionResult getIntersection(Path64 rectPath, Point64 p, Point64 p2, Location loc, Point64 ipRefObject) { ipRefObject.set(new Point64(0, 0)); - switch (locRefObject.argValue) { + switch (loc) { case left : if (getSegmentIntersection(p, p2, rectPath.get(0), rectPath.get(3), ipRefObject)) { - return true; + return new IntersectionResult(true, loc); } if (p.y < rectPath.get(0).y && getSegmentIntersection(p, p2, rectPath.get(0), rectPath.get(1), ipRefObject)) { - locRefObject.argValue = Location.top; - return true; + return new IntersectionResult(true, Location.top); } if (!getSegmentIntersection(p, p2, rectPath.get(2), rectPath.get(3), ipRefObject)) { - return false; + return new IntersectionResult(false, loc); } - locRefObject.argValue = Location.bottom; - return true; + return new IntersectionResult(true, Location.bottom); case right : if (getSegmentIntersection(p, p2, rectPath.get(1), rectPath.get(2), ipRefObject)) { - return true; + return new IntersectionResult(true, loc); } if (p.y < rectPath.get(0).y && getSegmentIntersection(p, p2, rectPath.get(0), rectPath.get(1), ipRefObject)) { - locRefObject.argValue = Location.top; - return true; + return new IntersectionResult(true, Location.top); } if (!getSegmentIntersection(p, p2, rectPath.get(2), rectPath.get(3), ipRefObject)) { - return false; + return new IntersectionResult(false, loc); } - locRefObject.argValue = Location.bottom; - return true; + return new IntersectionResult(true, Location.bottom); case top : if (getSegmentIntersection(p, p2, rectPath.get(0), rectPath.get(1), ipRefObject)) { - return true; + return new IntersectionResult(true, loc); } if (p.x < rectPath.get(0).x && getSegmentIntersection(p, p2, rectPath.get(0), rectPath.get(3), ipRefObject)) { - locRefObject.argValue = Location.left; - return true; + return new IntersectionResult(true, Location.left); } if (p.x <= rectPath.get(1).x || !getSegmentIntersection(p, p2, rectPath.get(1), rectPath.get(2), ipRefObject)) { - return false; + return new IntersectionResult(false, loc); } - locRefObject.argValue = Location.right; - return true; + return new IntersectionResult(true, Location.right); case bottom : if (getSegmentIntersection(p, p2, rectPath.get(2), rectPath.get(3), ipRefObject)) { - return true; + return new IntersectionResult(true, loc); } if (p.x < rectPath.get(3).x && getSegmentIntersection(p, p2, rectPath.get(0), rectPath.get(3), ipRefObject)) { - locRefObject.argValue = Location.left; - return true; + return new IntersectionResult(true, Location.left); } if (p.x <= rectPath.get(2).x || !getSegmentIntersection(p, p2, rectPath.get(1), rectPath.get(2), ipRefObject)) { - return false; + return new IntersectionResult(false, loc); } - locRefObject.argValue = Location.right; - return true; + return new IntersectionResult(true, Location.right); default : if (getSegmentIntersection(p, p2, rectPath.get(0), rectPath.get(3), ipRefObject)) { - locRefObject.argValue = Location.left; - return true; + return new IntersectionResult(true, Location.left); } if (getSegmentIntersection(p, p2, rectPath.get(0), rectPath.get(1), ipRefObject)) { - locRefObject.argValue = Location.top; - return true; + return new IntersectionResult(true, Location.top); } if (getSegmentIntersection(p, p2, rectPath.get(1), rectPath.get(2), ipRefObject)) { - locRefObject.argValue = Location.right; - return true; + return new IntersectionResult(true, Location.right); } if (!getSegmentIntersection(p, p2, rectPath.get(2), rectPath.get(3), ipRefObject)) { - return false; + return new IntersectionResult(false, loc); } - locRefObject.argValue = Location.bottom; - return true; + return new IntersectionResult(true, Location.bottom); } } - protected void getNextLocation(Path64 path, RefObject locRefObject, RefObject iRefObject, int highI) { - Location loc = locRefObject.argValue; - int i = iRefObject.argValue; + protected NextLocationResult getNextLocation(Path64 path, Location loc, int i, int highI) { switch (loc) { case left : while (i <= highI && path.get(i).x <= rect_.left) { @@ -481,8 +492,7 @@ protected void getNextLocation(Path64 path, RefObject locRefObject, Re } break; } - locRefObject.argValue = loc; - iRefObject.argValue = i; + return new NextLocationResult(loc, i); } private static boolean startLocsAreClockwise(List locs) { @@ -519,14 +529,20 @@ protected void executeInternal(Path64 path) { Location prev = Location.inside; int highI = path.size() - 1; - RefObject locRefObject = new RefObject<>(); + Location loc = Location.inside; // find the location of the last point - if (!getLocation(rect_, path.get(highI), locRefObject)) { - prev = locRefObject.argValue; + LocationResult locRes = getLocation(rect_, path.get(highI)); + loc = locRes.location; + if (!locRes.outside) { + prev = loc; int j = highI - 1; - RefObject prevRefObject = new RefObject<>(prev); - while (j >= 0 && !getLocation(rect_, path.get(j), prevRefObject)) { + LocationResult prevLocRes = new LocationResult(false, prev); + while (j >= 0) { + prevLocRes = getLocation(rect_, path.get(j)); + if (prevLocRes.outside) { + break; + } j--; } if (j < 0) { @@ -536,53 +552,51 @@ protected void executeInternal(Path64 path) { } return; } - prev = prevRefObject.argValue; + prev = prevLocRes.location; if (prev == Location.inside) { - locRefObject.argValue = Location.inside; + loc = Location.inside; } } // **capture the very first loc** for the tail‐end test - Location startingLoc = locRefObject.argValue; + Location startingLoc = loc; // ––– main loop int i = 0; while (i <= highI) { - prev = locRefObject.argValue; + prev = loc; Location prevCrossLoc = crossingLoc; // advance i to the next index where the rect‐location changes - RefObject iRefObject = new RefObject<>(i); - getNextLocation(path, locRefObject, iRefObject, highI); - i = iRefObject.argValue; + NextLocationResult nextLoc = getNextLocation(path, loc, i, highI); + loc = nextLoc.location; + i = nextLoc.index; if (i > highI) { break; } // current segment runs from path[i-1] to path[i] Point64 prevPt = (i == 0) ? path.get(highI) : path.get(i - 1); - crossingLoc = locRefObject.argValue; + crossingLoc = loc; // see if that segment hits the rectangle boundary - RefObject crossRefObject = new RefObject<>(crossingLoc); Point64 ipRefObject = new Point64(); - if (!getIntersection(rectPath_, path.get(i), prevPt, crossRefObject, ipRefObject)) { + IntersectionResult crossRes = getIntersection(rectPath_, path.get(i), prevPt, crossingLoc, ipRefObject); + if (!crossRes.intersects) { // still entirely outside - crossingLoc = crossRefObject.argValue; + crossingLoc = crossRes.location; if (prevCrossLoc == Location.inside) { - boolean cw = isClockwise(prev, locRefObject.argValue, prevPt, path.get(i), mp_); + boolean cw = isClockwise(prev, loc, prevPt, path.get(i), mp_); do { startLocs.add(prev); prev = getAdjacentLocation(prev, cw); - } while (prev != locRefObject.argValue); + } while (prev != loc); crossingLoc = prevCrossLoc; - } else if (prev != Location.inside && prev != locRefObject.argValue) { - boolean cw = isClockwise(prev, locRefObject.argValue, prevPt, path.get(i), mp_); - RefObject pRefObject = new RefObject<>(prev); + } else if (prev != Location.inside && prev != loc) { + boolean cw = isClockwise(prev, loc, prevPt, path.get(i), mp_); do { - addCorner(pRefObject, cw); - prev = pRefObject.argValue; - } while (prev != locRefObject.argValue); + prev = addCorner(prev, cw); + } while (prev != loc); } // **only place we increment i in the no‐intersection case** @@ -591,28 +605,29 @@ protected void executeInternal(Path64 path) { } // we *did* intersect - crossingLoc = crossRefObject.argValue; + crossingLoc = crossRes.location; Point64 ip = ipRefObject; - if (locRefObject.argValue == Location.inside) { + if (loc == Location.inside) { // entering rectangle if (firstCross == Location.inside) { firstCross = crossingLoc; startLocs.add(prev); } else if (prev != crossingLoc) { boolean cw = isClockwise(prev, crossingLoc, prevPt, path.get(i), mp_); - RefObject pRefObject = new RefObject<>(prev); do { - addCorner(pRefObject, cw); - prev = pRefObject.argValue; + prev = addCorner(prev, cw); } while (prev != crossingLoc); } } else if (prev != Location.inside) { // passing all the way through - RefObject loc2RefObject = new RefObject<>(prev); Point64 ip2RefObject = new Point64(); - getIntersection(rectPath_, prevPt, path.get(i), loc2RefObject, ip2RefObject); - Location newLoc = loc2RefObject.argValue; + IntersectionResult loc2Res = getIntersection(rectPath_, prevPt, path.get(i), prev, ip2RefObject); + if (!loc2Res.intersects) { + i++; + continue; + } + Location newLoc = loc2Res.location; if (prevCrossLoc != Location.inside && prevCrossLoc != newLoc) { addCorner(prevCrossLoc, newLoc); @@ -621,22 +636,19 @@ protected void executeInternal(Path64 path) { firstCross = newLoc; startLocs.add(prev); } - locRefObject.argValue = crossingLoc; + loc = crossingLoc; add(ip2RefObject); if (ip.equals(ip2RefObject)) { - RefObject tmpRefObject = new RefObject<>(crossingLoc); - RefObject onRectRefObject = new RefObject<>(); - getLocation(rect_, path.get(i), onRectRefObject); - addCorner(tmpRefObject, headingClockwise(tmpRefObject.argValue, onRectRefObject.argValue)); - crossingLoc = tmpRefObject.argValue; + Location onRectLoc = getLocation(rect_, path.get(i)).location; + crossingLoc = addCorner(crossingLoc, headingClockwise(crossingLoc, onRectLoc)); i++; continue; } } else { // exiting rectangle - locRefObject.argValue = crossingLoc; + loc = crossingLoc; if (firstCross == Location.inside) { firstCross = crossingLoc; } @@ -661,23 +673,20 @@ protected void executeInternal(Path64 path) { add(rectPath_.get(k)); addToEdge(edges_[k * 2], results_.get(0)); } - } else if (locRefObject.argValue != Location.inside && (locRefObject.argValue != firstCross || startLocs.size() > 2)) { + } else if (loc != Location.inside && (loc != firstCross || startLocs.size() > 2)) { if (!startLocs.isEmpty()) { - prev = locRefObject.argValue; + prev = loc; for (Location loc2 : startLocs) { if (prev == loc2) { continue; } boolean c = headingClockwise(prev, loc2); - RefObject pRefObject = new RefObject<>(prev); - addCorner(pRefObject, c); - prev = pRefObject.argValue; + prev = addCorner(prev, c); } - locRefObject.argValue = prev; + loc = prev; } - if (locRefObject.argValue != firstCross) { - RefObject pRefObject = new RefObject<>(locRefObject.argValue); - addCorner(pRefObject, headingClockwise(locRefObject.argValue, firstCross)); + if (loc != firstCross) { + loc = addCorner(loc, headingClockwise(loc, firstCross)); } } } diff --git a/src/main/java/clipper2/rectclip/RectClipLines64.java b/src/main/java/clipper2/rectclip/RectClipLines64.java index 280f77b..7aca250 100644 --- a/src/main/java/clipper2/rectclip/RectClipLines64.java +++ b/src/main/java/clipper2/rectclip/RectClipLines64.java @@ -5,7 +5,6 @@ import clipper2.core.Paths64; import clipper2.core.Point64; import clipper2.core.Rect64; -import tangible.RefObject; /** * RectClipLines64 intersects subject open paths (polylines) with the specified @@ -72,11 +71,17 @@ protected void executeInternal(Path64 path) { if (path.size() < 2 || rect_.IsEmpty()) { return; } - RefObject locRefObject = new RefObject<>(Location.inside); + Location loc = Location.inside; int i = 1, highI = path.size() - 1; - if (!getLocation(rect_, path.get(0), locRefObject)) { - RefObject prevRefObject = new RefObject<>(locRefObject.argValue); - while (i <= highI && !getLocation(rect_, path.get(i), prevRefObject)) { + LocationResult locRes = getLocation(rect_, path.get(0)); + loc = locRes.location; + if (!locRes.outside) { + LocationResult prevLocRes = new LocationResult(false, loc); + while (i <= highI) { + prevLocRes = getLocation(rect_, path.get(i)); + if (prevLocRes.outside) { + break; + } i++; } if (i > highI) { @@ -85,36 +90,38 @@ protected void executeInternal(Path64 path) { } return; } - if (prevRefObject.argValue == Location.inside) { - locRefObject.argValue = Location.inside; + if (prevLocRes.location == Location.inside) { + loc = Location.inside; } i = 1; } - if (locRefObject.argValue == Location.inside) { + if (loc == Location.inside) { add(path.get(0)); } while (i <= highI) { - Location prev = locRefObject.argValue; - RefObject iRefObject = new RefObject<>(i); - getNextLocation(path, locRefObject, iRefObject, highI); - i = iRefObject.argValue; + Location prev = loc; + NextLocationResult nextLoc = getNextLocation(path, loc, i, highI); + loc = nextLoc.location; + i = nextLoc.index; if (i > highI) { break; } Point64 prevPt = path.get(i - 1); - RefObject crossRefObject = new RefObject<>(locRefObject.argValue); Point64 ipRefObject = new Point64(); - if (!getIntersection(rectPath_, path.get(i), prevPt, crossRefObject, ipRefObject)) { + IntersectionResult crossRes = getIntersection(rectPath_, path.get(i), prevPt, loc, ipRefObject); + if (!crossRes.intersects) { i++; continue; } Point64 ip = ipRefObject; - if (locRefObject.argValue == Location.inside) { + if (loc == Location.inside) { add(ip, true); } else if (prev != Location.inside) { Point64 ip2RefObject = new Point64(); - getIntersection(rectPath_, prevPt, path.get(i), new RefObject<>(prev), ip2RefObject); - add(ip2RefObject, true); + IntersectionResult crossRes2 = getIntersection(rectPath_, prevPt, path.get(i), prev, ip2RefObject); + if (crossRes2.intersects) { + add(ip2RefObject, true); + } add(ip, true); } else { add(ip); @@ -122,4 +129,4 @@ protected void executeInternal(Path64 path) { i++; } } -} \ No newline at end of file +} diff --git a/src/main/java/tangible/OutObject.java b/src/main/java/tangible/OutObject.java deleted file mode 100644 index 72f83c6..0000000 --- a/src/main/java/tangible/OutObject.java +++ /dev/null @@ -1,11 +0,0 @@ -package tangible; - -//---------------------------------------------------------------------------------------- -// Copyright © 2007 - 2020 Tangible Software Solutions, Inc. -// This class can be used by anyone provided that the copyright notice remains intact. -// -// This class is used to replicate the ability to have 'out' parameters in Java. -//---------------------------------------------------------------------------------------- -public class OutObject { - public T argValue; -} \ No newline at end of file diff --git a/src/main/java/tangible/RefObject.java b/src/main/java/tangible/RefObject.java deleted file mode 100644 index 8533da2..0000000 --- a/src/main/java/tangible/RefObject.java +++ /dev/null @@ -1,18 +0,0 @@ -package tangible; - -//---------------------------------------------------------------------------------------- -// Copyright © 2007 - 2020 Tangible Software Solutions, Inc. -// This class can be used by anyone provided that the copyright notice remains intact. -// -// This class is used to replicate the ability to pass arguments by reference in Java. -//---------------------------------------------------------------------------------------- -public final class RefObject extends OutObject { - public T argValue; - - public RefObject() { - } - - public RefObject(T refArg) { - argValue = refArg; - } -} \ No newline at end of file diff --git a/src/main/java9/module-info.java b/src/main/java9/module-info.java index aac5d70..2cfe063 100644 --- a/src/main/java9/module-info.java +++ b/src/main/java9/module-info.java @@ -4,6 +4,4 @@ exports clipper2.engine; exports clipper2.offset; exports clipper2.rectclip; - - exports tangible; -} \ No newline at end of file +} diff --git a/src/test/java/clipper2/TestPolytree.java b/src/test/java/clipper2/TestPolytree.java index b0257c0..0096d87 100644 --- a/src/test/java/clipper2/TestPolytree.java +++ b/src/test/java/clipper2/TestPolytree.java @@ -22,7 +22,6 @@ import clipper2.engine.PolyPath64; import clipper2.engine.PolyPathBase; import clipper2.engine.PolyTree64; -import tangible.RefObject; class TestPolytree { @@ -119,26 +118,25 @@ private static boolean PolytreeContainsPoint(PolyTree64 pp, Point64 pt) { int counter = 0; for (int i = 0; i < pp.getCount(); i++) { PolyPath64 child = pp.get(i); - tangible.RefObject tempRef_counter = new RefObject<>(counter); - PolyPathContainsPoint(child, pt, tempRef_counter); - counter = tempRef_counter.argValue; + counter = PolyPathContainsPoint(child, pt, counter); } assertTrue(counter >= 0, "Polytree has too many holes"); return counter != 0; } - private static void PolyPathContainsPoint(PolyPath64 pp, Point64 pt, RefObject counter) { + private static int PolyPathContainsPoint(PolyPath64 pp, Point64 pt, int counter) { if (Clipper.PointInPolygon(pt, pp.getPolygon()) != PointInPolygonResult.IsOutside) { if (pp.getIsHole()) { - counter.argValue--; + counter--; } else { - counter.argValue++; + counter++; } } for (int i = 0; i < pp.getCount(); i++) { PolyPath64 child = pp.get(i); - PolyPathContainsPoint(child, pt, counter); + counter = PolyPathContainsPoint(child, pt, counter); } + return counter; } }