Skip to content

Commit 41a1710

Browse files
authored
Merge v1.2.0 from elara-leitstellentechnik
2 parents bea64f3 + c59c6c7 commit 41a1710

24 files changed

+2477
-2132
lines changed

src/main/java/clipper2/Clipper.java

Lines changed: 315 additions & 158 deletions
Large diffs are not rendered by default.

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

Lines changed: 117 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,24 @@
44

55
public final class InternalClipper {
66

7+
private static final long MaxInt64 = 9223372036854775807L;
8+
private static final long MaxCoord = MaxInt64 / 4;
9+
private static final double max_coord = MaxCoord;
10+
private static final double min_coord = -MaxCoord;
11+
private static final long Invalid64 = MaxInt64;
12+
13+
public static final double DEFAULT_ARC_TOLERANCE = 0.25;
714
private static final double FLOATING_POINT_TOLERANCE = 1E-12;
815
private static final double DEFAULT_MIN_EDGE_LENGTH = 0.1;
916

17+
private static final String PRECISION_RANGE_ERROR = "Error: Precision is out of range.";
18+
19+
public static void CheckPrecision(int precision)
20+
{
21+
if (precision < -8 || precision > 8)
22+
throw new IllegalArgumentException(PRECISION_RANGE_ERROR);
23+
}
24+
1025
private InternalClipper() {
1126
}
1227

@@ -30,75 +45,50 @@ public static double DotProduct(PointD vec1, PointD vec2) {
3045
return (vec1.x * vec2.x + vec1.y * vec2.y);
3146
}
3247

33-
public static boolean GetIntersectPoint64(Point64 ln1a, Point64 ln1b, Point64 ln2a, Point64 ln2b, /* out */ Point64 ip) {
34-
double m1, b1, m2, b2;
35-
if (ln1b.x == ln1a.x) {
36-
if (ln2b.x == ln2a.x) {
37-
return false;
38-
}
39-
m2 = (double) (ln2b.y - ln2a.y) / (ln2b.x - ln2a.x);
40-
b2 = ln2a.y - m2 * ln2a.x;
41-
ip.x = ln1a.x;
42-
ip.y = Math.round(m2 * ln1a.x + b2);
43-
} else if (ln2b.x == ln2a.x) {
44-
m1 = (double) (ln1b.y - ln1a.y) / (ln1b.x - ln1a.x);
45-
b1 = ln1a.y - m1 * ln1a.x;
46-
ip.x = ln2a.x;
47-
ip.y = Math.round(m1 * ln2a.x + b1);
48-
} else {
49-
m1 = (double) (ln1b.y - ln1a.y) / (ln1b.x - ln1a.x);
50-
b1 = ln1a.y - m1 * ln1a.x;
51-
m2 = (double) (ln2b.y - ln2a.y) / (ln2b.x - ln2a.x);
52-
b2 = ln2a.y - m2 * ln2a.x;
53-
if (Math.abs(m1 - m2) > FLOATING_POINT_TOLERANCE) {
54-
double x = (b2 - b1) / (m1 - m2);
55-
ip.x = Math.round(x);
56-
ip.y = Math.round(m1 * x + b1);
57-
} else {
58-
ip.x = Math.round((ln1a.x + ln1b.x) * 0.5);
59-
ip.y = Math.round((ln1a.y + ln1b.y) * 0.5);
60-
}
48+
public static long CheckCastInt64(double val)
49+
{
50+
if ((val >= max_coord) || (val <= min_coord)) return Invalid64;
51+
return (long)Math.rint(val);
52+
}
53+
54+
public static boolean GetIntersectPt(Point64 ln1a, Point64 ln1b, Point64 ln2a, Point64 ln2b, /*out*/ Point64 ip)
55+
{
56+
double dy1 = (ln1b.y - ln1a.y);
57+
double dx1 = (ln1b.x - ln1a.x);
58+
double dy2 = (ln2b.y - ln2a.y);
59+
double dx2 = (ln2b.x - ln2a.x);
60+
double cp = dy1 * dx2 - dy2 * dx1;
61+
if (cp == 0.0) {
62+
return false;
6163
}
62-
return true;
64+
double qx = dx1 * ln1a.y - dy1 * ln1a.x;
65+
double qy = dx2 * ln2a.y - dy2 * ln2a.x;
66+
ip.x = CheckCastInt64((dx1 * qy - dx2 * qx) / cp);
67+
ip.y = CheckCastInt64((dy1 * qy - dy2 * qx) / cp);
68+
return (ip.x != Invalid64 && ip.y != Invalid64);
6369
}
6470

6571
public static boolean GetIntersectPoint(Point64 ln1a, Point64 ln1b, Point64 ln2a, Point64 ln2b, /* out */ PointD ip) {
66-
double m1, b1, m2, b2;
67-
if (ln1b.x == ln1a.x) {
68-
if (ln2b.x == ln2a.x) {
69-
return false;
70-
}
71-
m2 = (double) (ln2b.y - ln2a.y) / (ln2b.x - ln2a.x);
72-
b2 = ln2a.y - m2 * ln2a.x;
73-
ip.x = ln1a.x;
74-
ip.y = m2 * ln1a.x + b2;
75-
} else if (ln2b.x == ln2a.x) {
76-
m1 = (double) (ln1b.y - ln1a.y) / (ln1b.x - ln1a.x);
77-
b1 = ln1a.y - m1 * ln1a.x;
78-
ip.x = ln2a.x;
79-
ip.y = m1 * ln2a.x + b1;
80-
} else {
81-
m1 = (double) (ln1b.y - ln1a.y) / (ln1b.x - ln1a.x);
82-
b1 = ln1a.y - m1 * ln1a.x;
83-
m2 = (double) (ln2b.y - ln2a.y) / (ln2b.x - ln2a.x);
84-
b2 = ln2a.y - m2 * ln2a.x;
85-
if (Math.abs(m1 - m2) > FLOATING_POINT_TOLERANCE) {
86-
ip.x = (b2 - b1) / (m1 - m2);
87-
ip.y = m1 * ip.x + b1;
88-
} else {
89-
ip.x = (ln1a.x + ln1b.x) * 0.5;
90-
ip.y = (ln1a.y + ln1b.y) * 0.5;
91-
}
72+
double dy1 = (ln1b.y - ln1a.y);
73+
double dx1 = (ln1b.x - ln1a.x);
74+
double dy2 = (ln2b.y - ln2a.y);
75+
double dx2 = (ln2b.x - ln2a.x);
76+
double q1 = dy1 * ln1a.x - dx1 * ln1a.y;
77+
double q2 = dy2 * ln2a.x - dx2 * ln2a.y;
78+
double cross_prod = dy1 * dx2 - dy2 * dx1;
79+
if (cross_prod == 0.0) {
80+
return false;
9281
}
93-
82+
ip.x = (dx2 * q1 - dx1 * q2) / cross_prod;
83+
ip.y = (dy2 * q1 - dy1 * q2) / cross_prod;
9484
return true;
9585
}
9686

97-
public static boolean SegmentsIntersect(Point64 seg1a, Point64 seg1b, Point64 seg2a, Point64 seg2b) {
98-
return SegmentsIntersect(seg1a, seg1b, seg2a, seg2b, false);
87+
public static boolean SegsIntersect(Point64 seg1a, Point64 seg1b, Point64 seg2a, Point64 seg2b) {
88+
return SegsIntersect(seg1a, seg1b, seg2a, seg2b, false);
9989
}
10090

101-
public static boolean SegmentsIntersect(Point64 seg1a, Point64 seg1b, Point64 seg2a, Point64 seg2b, boolean inclusive) {
91+
public static boolean SegsIntersect(Point64 seg1a, Point64 seg1b, Point64 seg2a, Point64 seg2b, boolean inclusive) {
10292
if (inclusive) {
10393
double res1 = CrossProduct(seg1a, seg2a, seg2b);
10494
double res2 = CrossProduct(seg1b, seg2a, seg2b);
@@ -113,75 +103,93 @@ public static boolean SegmentsIntersect(Point64 seg1a, Point64 seg1b, Point64 se
113103
// ensure NOT collinear
114104
return (res1 != 0 || res2 != 0 || res3 != 0 || res4 != 0);
115105
} else {
116-
double dx1 = seg1a.x - seg1b.x;
117-
double dy1 = seg1a.y - seg1b.y;
118-
double dx2 = seg2a.x - seg2b.x;
119-
double dy2 = seg2a.y - seg2b.y;
120-
return (((dy1 * (seg2a.x - seg1a.x) - dx1 * (seg2a.y - seg1a.y))
121-
* (dy1 * (seg2b.x - seg1a.x) - dx1 * (seg2b.y - seg1a.y)) < 0)
122-
&& ((dy2 * (seg1a.x - seg2a.x) - dx2 * (seg1a.y - seg2a.y))
123-
* (dy2 * (seg1b.x - seg2a.x) - dx2 * (seg1b.y - seg2a.y)) < 0));
106+
return (CrossProduct(seg1a, seg2a, seg2b) *
107+
CrossProduct(seg1b, seg2a, seg2b) < 0) &&
108+
(CrossProduct(seg2a, seg1a, seg1b) *
109+
CrossProduct(seg2b, seg1a, seg1b) < 0);
124110
}
125111
}
126112

127-
public static PointInPolygonResult PointInPolygon(Point64 pt, Path64 polygon) {
128-
int len = polygon.size(), i = len - 1;
113+
public static Point64 GetClosestPtOnSegment(Point64 offPt, Point64 seg1, Point64 seg2)
114+
{
115+
if (seg1.x == seg2.x && seg1.y == seg2.y) return seg1;
116+
double dx = (seg2.x - seg1.x);
117+
double dy = (seg2.y - seg1.y);
118+
double q = ((offPt.x - seg1.x) * dx +
119+
(offPt.y - seg1.y) * dy) / ((dx*dx) + (dy*dy));
120+
if (q < 0) q = 0; else if (q > 1) q = 1;
121+
return new Point64(
122+
seg1.x + Math.rint(q * dx), seg1.y + Math.rint(q* dy));
123+
}
129124

125+
public static PointInPolygonResult PointInPolygon(Point64 pt, Path64 polygon) {
126+
int len = polygon.size(), start = 0;
130127
if (len < 3) {
131128
return PointInPolygonResult.IsOutside;
132129
}
133130

134-
while (i >= 0 && polygon.get(i).y == pt.y) {
135-
--i;
136-
}
137-
if (i < 0) {
131+
while (start < len && polygon.get(start).y == pt.y) start++;
132+
if (start == len) {
138133
return PointInPolygonResult.IsOutside;
139134
}
140135

141-
int val = 0;
142-
boolean isAbove = polygon.get(i).y < pt.y;
143-
i = 0;
136+
double d;
137+
boolean isAbove = polygon.get(start).y < pt.y, startingAbove = isAbove;
138+
int val = 0, i = start + 1, end = len;
139+
while (true) {
140+
if (i == end) {
141+
if (end == 0 || start == 0) {
142+
break;
143+
}
144+
end = start;
145+
i = 0;
146+
}
144147

145-
while (i < len) {
146148
if (isAbove) {
147-
while (i < len && polygon.get(i).y < pt.y) {
149+
while (i < end && polygon.get(i).y < pt.y) {
148150
i++;
149151
}
150-
if (i == len) {
151-
break;
152+
if (i == end) {
153+
continue;
152154
}
153155
} else {
154-
while (i < len && polygon.get(i).y > pt.y) {
156+
while (i < end && polygon.get(i).y > pt.y) {
155157
i++;
156158
}
157-
if (i == len) {
158-
break;
159+
if (i == end) {
160+
continue;
159161
}
160162
}
161163

162-
Point64 prev;
163-
164-
Point64 curr = polygon.get(i);
164+
Point64 curr = polygon.get(i), prev;
165165
if (i > 0) {
166166
prev = polygon.get(i - 1);
167167
} else {
168168
prev = polygon.get(len - 1);
169169
}
170170

171-
if (curr.y == pt.y) {
172-
if (curr.x == pt.x || (curr.y == prev.y && ((pt.x < prev.x) != (pt.x < curr.x)))) {
171+
if (curr.y == pt.y)
172+
{
173+
if (curr.x == pt.x || (curr.y == prev.y &&
174+
((pt.x < prev.x) != (pt.x < curr.x)))) {
173175
return PointInPolygonResult.IsOn;
174176
}
175177
i++;
178+
if (i == start) {
179+
break;
180+
}
176181
continue;
177182
}
178183

179-
if (pt.x < curr.x && pt.x < prev.x) {
184+
if (pt.x < curr.x && pt.x < prev.x)
185+
{
180186
// we're only interested in edges crossing on the left
181-
} else if (pt.x > prev.x && pt.x > curr.x) {
187+
}
188+
else if (pt.x > prev.x && pt.x > curr.x)
189+
{
182190
val = 1 - val; // toggle val
183191
} else {
184-
double d = CrossProduct(prev, curr, pt);
192+
d = CrossProduct(prev, curr, pt);
185193
if (d == 0) {
186194
return PointInPolygonResult.IsOn;
187195
}
@@ -192,6 +200,24 @@ public static PointInPolygonResult PointInPolygon(Point64 pt, Path64 polygon) {
192200
isAbove = !isAbove;
193201
i++;
194202
}
203+
204+
if (isAbove != startingAbove) {
205+
if (i == len) {
206+
i = 0;
207+
}
208+
if (i == 0) {
209+
d = CrossProduct(polygon.get(len - 1), polygon.get(0), pt);
210+
} else {
211+
d = CrossProduct(polygon.get(i - 1), polygon.get(i), pt);
212+
}
213+
if (d == 0) {
214+
return PointInPolygonResult.IsOn;
215+
}
216+
if ((d < 0) == isAbove) {
217+
val = 1 - val;
218+
}
219+
}
220+
195221
if (val == 0) {
196222
return PointInPolygonResult.IsOutside;
197223
}

src/main/java/clipper2/core/Path64.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,12 @@ public Path64(Point64... path) {
3232
super(Arrays.asList(path));
3333
}
3434

35+
@Override
36+
public String toString() {
37+
String s = "";
38+
for (Point64 p : this)
39+
s = s + p.toString() + " ";
40+
return s;
41+
}
42+
3543
}

src/main/java/clipper2/core/PathD.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,12 @@ public PathD(List<PointD> path) {
2727
super(path);
2828
}
2929

30+
@Override
31+
public String toString() {
32+
String s = "";
33+
for (PointD p : this)
34+
s = s + p.toString() + " ";
35+
return s;
36+
}
37+
3038
}

src/main/java/clipper2/core/Paths64.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,12 @@ public Paths64(Path64... paths) {
2828
super(Arrays.asList(paths));
2929
}
3030

31+
@Override
32+
public String toString() {
33+
String s = "";
34+
for (Path64 p : this)
35+
s = s + p.toString() + "\n";
36+
return s;
37+
}
38+
3139
}

src/main/java/clipper2/core/PathsD.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,12 @@ public PathsD(List<PathD> paths) {
2323
super(paths);
2424
}
2525

26+
@Override
27+
public String toString() {
28+
String s = "";
29+
for (PathD p : this)
30+
s = s + p.toString() + "\n";
31+
return s;
32+
}
33+
2634
}

src/main/java/clipper2/core/Rect64.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,34 @@ public final class Rect64 {
66
public long top;
77
public long right;
88
public long bottom;
9+
private static final String InvalidRect = "Invalid Rect64 assignment";
910

1011
public Rect64() {
1112
}
1213

1314
public Rect64(long l, long t, long r, long b) {
15+
if (r < l || b < t)
16+
throw new IllegalArgumentException(InvalidRect);
1417
left = l;
1518
top = t;
1619
right = r;
1720
bottom = b;
1821
}
1922

23+
public Rect64(boolean isValid) {
24+
if (isValid) {
25+
left = 0;
26+
top = 0;
27+
right = 0;
28+
bottom = 0;
29+
} else {
30+
left = Long.MAX_VALUE;
31+
top = Long.MAX_VALUE;
32+
right = Long.MIN_VALUE;
33+
bottom = Long.MIN_VALUE;
34+
}
35+
}
36+
2037
public Rect64(Rect64 rec) {
2138
left = rec.left;
2239
top = rec.top;
@@ -62,7 +79,8 @@ public boolean Contains(Point64 pt) {
6279
}
6380

6481
public boolean Intersects(Rect64 rec) {
65-
return (Math.max(left, rec.left) < Math.min(right, rec.right)) && (Math.max(top, rec.top) < Math.min(bottom, rec.bottom));
82+
return (Math.max(left, rec.left) <= Math.min(right, rec.right)) &&
83+
(Math.max(top, rec.top) <= Math.min(bottom, rec.bottom));
6684
}
6785

6886
public boolean Contains(Rect64 rec) {

0 commit comments

Comments
 (0)