Skip to content

Commit b3f21bd

Browse files
committed
1.5.0
1 parent 842e2e6 commit b3f21bd

8 files changed

Lines changed: 114 additions & 90 deletions

File tree

src/main/java/clipper2/Clipper.java

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public static void BooleanOp(ClipType clipType, @Nullable PathsD subject, @Nulla
226226
* @see #InflatePaths(PathsD, double, JoinType, EndType, double, double, int)
227227
*/
228228
public static Paths64 InflatePaths(Paths64 paths, double delta, JoinType joinType, EndType endType) {
229-
return InflatePaths(paths, delta, joinType, endType, 2.0, 0.25);
229+
return InflatePaths(paths, delta, joinType, endType, 2.0, 0.0);
230230
}
231231

232232
/**
@@ -244,14 +244,14 @@ public static Paths64 InflatePaths(Paths64 paths, double delta, JoinType joinTyp
244244
* @see #InflatePaths(PathsD, double, JoinType, EndType, double, double, int)
245245
*/
246246
public static PathsD InflatePaths(PathsD paths, double delta, JoinType joinType, EndType endType, double miterLimit) {
247-
return InflatePaths(paths, delta, joinType, endType, miterLimit, 0.25, 8);
247+
return InflatePaths(paths, delta, joinType, endType, miterLimit, 0.0, 8);
248248
}
249249

250250
/**
251251
* @see #InflatePaths(PathsD, double, JoinType, EndType, double, double, int)
252252
*/
253253
public static PathsD InflatePaths(PathsD paths, double delta, JoinType joinType, EndType endType) {
254-
return InflatePaths(paths, delta, joinType, endType, 2.0, 0.25, 8);
254+
return InflatePaths(paths, delta, joinType, endType, 2.0, 0.0, 8);
255255
}
256256

257257
/**
@@ -992,29 +992,33 @@ public static double PerpendicDistFromLineSqrd(Point64 pt, Point64 line1, Point6
992992
}
993993

994994
public static void RDP(Path64 path, int begin, int end, double epsSqrd, List<Boolean> flags) {
995-
int idx = 0;
996-
double maxD = 0;
997-
while (end > begin && path.get(begin).equals(path.get(end))) {
998-
flags.set(end--, false);
999-
}
1000-
for (int i = begin + 1; i < end; ++i) {
1001-
// PerpendicDistFromLineSqrd - avoids expensive Sqrt()
1002-
double d = PerpendicDistFromLineSqrd(path.get(i), path.get(begin), path.get(end));
1003-
if (d <= maxD) {
995+
while (true) {
996+
int idx = 0;
997+
double maxD = 0;
998+
while (end > begin && path.get(begin).equals(path.get(end))) {
999+
flags.set(end--, false);
1000+
}
1001+
for (int i = begin + 1; i < end; ++i) {
1002+
// PerpendicDistFromLineSqrd - avoids expensive Sqrt()
1003+
double d = PerpendicDistFromLineSqrd(path.get(i), path.get(begin), path.get(end));
1004+
if (d <= maxD) {
1005+
continue;
1006+
}
1007+
maxD = d;
1008+
idx = i;
1009+
}
1010+
if (maxD <= epsSqrd) {
1011+
return;
1012+
}
1013+
flags.set(idx, true);
1014+
if (idx > begin + 1) {
1015+
RDP(path, begin, idx, epsSqrd, flags);
1016+
}
1017+
if (idx < end - 1) {
1018+
begin = idx;
10041019
continue;
10051020
}
1006-
maxD = d;
1007-
idx = i;
1008-
}
1009-
if (maxD <= epsSqrd) {
1010-
return;
1011-
}
1012-
flags.set(idx, true);
1013-
if (idx > begin + 1) {
1014-
RDP(path, begin, idx, epsSqrd, flags);
1015-
}
1016-
if (idx < end - 1) {
1017-
RDP(path, idx, end, epsSqrd, flags);
1021+
break;
10181022
}
10191023
}
10201024

@@ -1081,29 +1085,33 @@ public static Paths64 RamerDouglasPeucker(Paths64 paths, double epsilon) {
10811085
}
10821086

10831087
public static void RDP(PathD path, int begin, int end, double epsSqrd, List<Boolean> flags) {
1084-
int idx = 0;
1085-
double maxD = 0;
1086-
while (end > begin && path.get(begin).equals(path.get(end))) {
1087-
flags.set(end--, false);
1088-
}
1089-
for (int i = begin + 1; i < end; ++i) {
1090-
// PerpendicDistFromLineSqrd - avoids expensive Sqrt()
1091-
double d = PerpendicDistFromLineSqrd(path.get(i), path.get(begin), path.get(end));
1092-
if (d <= maxD) {
1088+
while (true) {
1089+
int idx = 0;
1090+
double maxD = 0;
1091+
while (end > begin && path.get(begin).equals(path.get(end))) {
1092+
flags.set(end--, false);
1093+
}
1094+
for (int i = begin + 1; i < end; ++i) {
1095+
// PerpendicDistFromLineSqrd - avoids expensive Sqrt()
1096+
double d = PerpendicDistFromLineSqrd(path.get(i), path.get(begin), path.get(end));
1097+
if (d <= maxD) {
1098+
continue;
1099+
}
1100+
maxD = d;
1101+
idx = i;
1102+
}
1103+
if (maxD <= epsSqrd) {
1104+
return;
1105+
}
1106+
flags.set(idx, true);
1107+
if (idx > begin + 1) {
1108+
RDP(path, begin, idx, epsSqrd, flags);
1109+
}
1110+
if (idx < end - 1) {
1111+
begin = idx;
10931112
continue;
10941113
}
1095-
maxD = d;
1096-
idx = i;
1097-
}
1098-
if (maxD <= epsSqrd) {
1099-
return;
1100-
}
1101-
flags.set(idx, true);
1102-
if (idx > begin + 1) {
1103-
RDP(path, begin, idx, epsSqrd, flags);
1104-
}
1105-
if (idx < end - 1) {
1106-
RDP(path, idx, end, epsSqrd, flags);
1114+
break;
11071115
}
11081116
}
11091117

src/main/java/clipper2/Minkowski.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
import clipper2.core.PathsD;
88
import clipper2.core.Point64;
99

10-
public class Minkowski {
10+
public final class Minkowski {
11+
12+
private Minkowski() {
13+
}
1114

1215
public static Paths64 Sum(Path64 pattern, Path64 path, boolean isClosed) {
1316
return Clipper.Union(MinkowskiInternal(pattern, path, true, isClosed), FillRule.NonZero);
@@ -78,4 +81,4 @@ private static Paths64 MinkowskiInternal(Path64 pattern, Path64 path, boolean is
7881
return result;
7982
}
8083

81-
}
84+
}

src/main/java/clipper2/core/ClipType.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
*/
3131
public enum ClipType {
3232

33-
None,
33+
NoClip,
3434
/** Preserves regions covered by both subject and clip polygons */
3535
Intersection,
3636
/** Preserves regions covered by subject or clip polygons, or both polygons */
@@ -40,4 +40,4 @@ public enum ClipType {
4040
/** Preserves regions covered by subject or clip polygons, but not both */
4141
Xor;
4242

43-
}
43+
}

src/main/java/clipper2/core/InternalClipper.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ public final class InternalClipper {
88
public static final double MIN_COORD = -MAX_COORD;
99
private static final long Invalid64 = Long.MAX_VALUE;
1010

11-
public static final double DEFAULT_ARC_TOLERANCE = 0.25;
1211
private static final double FLOATING_POINT_TOLERANCE = 1E-12;
1312
// private static final double DEFAULT_MIN_EDGE_LENGTH = 0.1;
1413

@@ -297,7 +296,10 @@ private static boolean productsAreEqual(long a, long b, long c, long d) {
297296
}
298297

299298
private static int triSign(long x) {
300-
return x > 0 ? 1 : (x < 0 ? -1 : 0);
299+
if (x < 0) {
300+
return -1;
301+
}
302+
return x > 1 ? 1 : 0;
301303
}
302304

303305
}

src/main/java/clipper2/engine/ClipperBase.java

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
*/
2626
abstract class ClipperBase {
2727

28-
private ClipType cliptype = ClipType.None;
28+
private ClipType cliptype = ClipType.NoClip;
2929
private FillRule fillrule = FillRule.EvenOdd;
3030
private Active actives = null;
3131
private Active sel = null;
@@ -1670,7 +1670,7 @@ private void AdjustCurrXAndCopyToSEL(long topY) {
16701670
}
16711671

16721672
protected final void ExecuteInternal(ClipType ct, FillRule fillRule) {
1673-
if (ct == ClipType.None) {
1673+
if (ct == ClipType.NoClip) {
16741674
return;
16751675
}
16761676
fillrule = fillRule;
@@ -2723,25 +2723,36 @@ private void DoSplitOp(OutRec outrec, OutPt splitOp) {
27232723
prevOp.next = newOp2;
27242724
}
27252725

2726-
if (absArea2 > 1 && (absArea2 > absArea1 || ((area2 > 0) == (area1 > 0)))) {
2727-
OutRec newOutRec = NewOutRec();
2728-
newOutRec.owner = outrec.owner;
2729-
splitOp.outrec = newOutRec;
2730-
splitOp.next.outrec = newOutRec;
2726+
if (absArea2 <= 1 || (!(absArea2 > absArea1) && ((area2 > 0) != (area1 > 0)))) {
2727+
return;
2728+
}
27312729

2732-
if (usingPolytree) {
2733-
if (outrec.splits == null) {
2734-
outrec.splits = new ArrayList<>();
2735-
}
2736-
outrec.splits.add(newOutRec.idx);
2737-
}
2730+
OutRec newOutRec = NewOutRec();
2731+
newOutRec.owner = outrec.owner;
2732+
splitOp.outrec = newOutRec;
2733+
splitOp.next.outrec = newOutRec;
2734+
2735+
OutPt newOp = new OutPt(ip, newOutRec);
2736+
newOp.prev = splitOp.next;
2737+
newOp.next = splitOp;
2738+
newOutRec.pts = newOp;
2739+
splitOp.prev = newOp;
2740+
splitOp.next.next = newOp;
27382741

2739-
OutPt newOp = new OutPt(ip, newOutRec);
2740-
newOp.prev = splitOp.next;
2741-
newOp.next = splitOp;
2742-
newOutRec.pts = newOp;
2743-
splitOp.prev = newOp;
2744-
splitOp.next.next = newOp;
2742+
if (!usingPolytree) {
2743+
return;
2744+
}
2745+
2746+
if (Path1InsidePath2(prevOp, newOp)) {
2747+
if (newOutRec.splits == null) {
2748+
newOutRec.splits = new ArrayList<>();
2749+
}
2750+
newOutRec.splits.add(outrec.idx);
2751+
} else {
2752+
if (outrec.splits == null) {
2753+
outrec.splits = new ArrayList<>();
2754+
}
2755+
outrec.splits.add(newOutRec.idx);
27452756
}
27462757
// else { splitOp = null; splitOp.next = null; }
27472758
}

src/main/java/clipper2/engine/ClipperD.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
public class ClipperD extends ClipperBase {
1818

19+
private static final String PRECISION_RANGE_ERROR = "Error: Precision is out of range.";
1920
private double scale;
2021
private double invScale;
2122

@@ -28,7 +29,7 @@ public ClipperD() {
2829
*/
2930
public ClipperD(int roundingDecimalPrecision) {
3031
if (roundingDecimalPrecision < -8 || roundingDecimalPrecision > 8) {
31-
throw new IllegalArgumentException("Error - RoundingDecimalPrecision exceeds the allowed range.");
32+
throw new IllegalArgumentException(PRECISION_RANGE_ERROR);
3233
}
3334
scale = Math.pow(10, roundingDecimalPrecision);
3435
invScale = 1 / scale;
@@ -124,13 +125,13 @@ public boolean Execute(ClipType clipType, FillRule fillRule, PolyTreeD polytree,
124125
if (!success) {
125126
return false;
126127
}
127-
if (!oPaths.isEmpty()) {
128-
openPaths.ensureCapacity(oPaths.size());
129-
for (Path64 path : oPaths) {
130-
openPaths.add(Clipper.ScalePathD(path, invScale));
131-
}
128+
if (oPaths.isEmpty()) {
129+
return true;
130+
}
131+
openPaths.ensureCapacity(oPaths.size());
132+
for (Path64 path : oPaths) {
133+
openPaths.add(Clipper.ScalePathD(path, invScale));
132134
}
133-
134135
return true;
135136
}
136137

src/main/java/clipper2/offset/ClipperOffset.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@
6565
*/
6666
public class ClipperOffset {
6767

68-
private static double TOLERANCE = 1.0E-12;
68+
private static final double TOLERANCE = 1.0E-12;
69+
private static final double ARC_CONST = 0.002;
6970

7071
private final List<Group> groupList = new ArrayList<>();
7172
private Path64 pathOut = new Path64();
@@ -105,7 +106,7 @@ public ClipperOffset(double miterLimit, double arcTolerance) {
105106
* @see #ClipperOffset(double, double, boolean, boolean)
106107
*/
107108
public ClipperOffset(double miterLimit) {
108-
this(miterLimit, 0.25, false, false);
109+
this(miterLimit, 0.0, false, false);
109110
}
110111

111112
/**
@@ -114,7 +115,7 @@ public ClipperOffset(double miterLimit) {
114115
* @see #ClipperOffset(double, double, boolean, boolean)
115116
*/
116117
public ClipperOffset() {
117-
this(2.0, 0.25, false, false);
118+
this(2.0, 0.0, false, false);
118119
}
119120

120121
/**
@@ -151,7 +152,8 @@ public ClipperOffset() {
151152
* {{@link #AddPath(Path64, JoinType, EndType)
152153
* AddPath()} and
153154
* {@link #AddPaths(Paths64, JoinType, EndType)
154-
* AddPaths()}. The default arcTolerance is 0.25.
155+
* AddPaths()}. The default arcTolerance is 0.0, which
156+
* enables automatic scaling (offset radius / 500).
155157
* @param preserveCollinear When adjacent edges are collinear in closed path
156158
* solutions, the common vertex can safely be removed
157159
* to simplify the solution without altering path
@@ -460,7 +462,7 @@ private void DoRound(Path64 path, int j, int k, double angle) {
460462
// when deltaCallback is assigned, groupDelta won't be constant,
461463
// so we'll need to do the following calculations for *every* vertex.
462464
double absDelta = Math.abs(groupDelta);
463-
double arcTol = arcTolerance > 0.01 ? arcTolerance : Math.log10(2 + absDelta) * InternalClipper.DEFAULT_ARC_TOLERANCE;
465+
double arcTol = arcTolerance > 0.01 ? arcTolerance : absDelta * ARC_CONST;
464466
double stepsPer360 = Math.PI / Math.acos(1 - arcTol / absDelta);
465467
stepSin = Math.sin((2 * Math.PI) / stepsPer360);
466468
stepCos = Math.cos((2 * Math.PI) / stepsPer360);
@@ -530,13 +532,10 @@ private int OffsetPoint(Group group, Path64 path, int j, int k) {
530532

531533
if (cosA > -0.999 && (sinA * groupDelta < 0)) { // test for concavity first (#593)
532534
// is concave
535+
// Insert 3 points so concave joins create regions that the trailing union
536+
// operation can cleanly remove, including over-shrunk path reversals.
533537
pathOut.add(GetPerpendic(path.get(j), normals.get(k)));
534-
// this extra point is the only simple way to ensure that path reversals
535-
// (ie over-shrunk paths) are fully cleaned out with the trailing union op.
536-
// However it's probably safe to skip this whenever an angle is almost flat.
537-
if (cosA < 0.99) {
538-
pathOut.add(path.get(j)); // (#405)
539-
}
538+
pathOut.add(path.get(j)); // (#405, #873, #916)
540539
pathOut.add(GetPerpendic(path.get(j), normals.get(j)));
541540
} else if (cosA > 0.999 && joinType != JoinType.Round) {
542541
// almost straight - less than 2.5 degree (#424, #482, #526 & #724)
@@ -682,7 +681,7 @@ private void DoGroupOffset(Group group) {
682681
// arcTol - when arcTolerance is undefined (0) then curve imprecision
683682
// will be relative to the size of the offset (delta). Obviously very
684683
// large offsets will almost always require much less precision.
685-
double arcTol = arcTolerance > 0.01 ? arcTolerance : Math.log10(2 + absDelta) * InternalClipper.DEFAULT_ARC_TOLERANCE;
684+
double arcTol = arcTolerance > 0.01 ? arcTolerance : absDelta * ARC_CONST;
686685
double stepsPer360 = Math.PI / Math.acos(1 - arcTol / absDelta);
687686
stepSin = Math.sin((2 * Math.PI) / stepsPer360);
688687
stepCos = Math.cos((2 * Math.PI) / stepsPer360);

src/test/java/clipper2/ClipperFileIO.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ static List<TestCase> loadTestCases(String testFileName) throws IOException {
8787
lines.add("");
8888

8989
String caption = "";
90-
ClipType ct = ClipType.None;
90+
ClipType ct = ClipType.NoClip;
9191
FillRule fillRule = FillRule.EvenOdd;
9292
long area = 0;
9393
int count = 0;

0 commit comments

Comments
 (0)