Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 42a2f71

Browse files
authored
Fix half-plane interesection not correctly handling opposite parallel half-planes (#839)
* Fix typo in half-plane intersection * Fix handling of special cases in half-plane intersection code. Previous code for handling parallel half-planes of opposite orientation could fail in the specific case the two half-planes formed an empty intersection. Also fixed the explanation of special case handling.
1 parent 965a435 commit 42a2f71

File tree

1 file changed

+27
-13
lines changed

1 file changed

+27
-13
lines changed

src/geometry/halfplane-intersection.md

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,12 @@ Notice the half-plane $F$ makes $A$ and $E$ redundant in the intersection. So we
5555

5656
With all of this in mind, we have almost everything we need to actually implement the algorithm, but we still need to talk about some special cases. At the beginning of the article we said we would add a bounding box to take care of the cases where the intersection could be unbounded, so the only tricky case we actually need to handle is parallel half-planes. We can have two sub-cases: two half-planes can be parallel with the same direction or with opposite direction. The reason this case needs to be handled separately is because we will need to compute intersection points of half-plane lines to be able to check if a half-plane is redundant or not, and two parallel lines have no intersection point, so we need a special way to deal with them.
5757

58-
Notice that, because we're adding the bounding box to deal with the unbounded case, this also deals with the case where we have two adjacent parallel half-planes with opposite directions, since there will have to be at least one of the bounding-box half-planes in between these two (remember they are sorted by angle). Thus the only case we actually need to handle is having multiple half-planes with the same angle, and it turns out this is also very easy to handle: just keep the leftmost one and erase the rest, since the others will be completely redundant anyways.
58+
For the case of parallel half-planes of opposite orientation: Notice that, because we're adding the bounding box to deal with the unbounded case, this also deals with the case where we have two adjacent parallel half-planes with opposite directions after sorting, since there will have to be at least one of the bounding-box half-planes in between these two (remember they are sorted by angle).
5959

60+
* However, it is possible that, after removing some half-planes from the back of the deque, two parallel half-planes of opposite direction end up together. This case only happens, specifically, when these two half-planes form an empty intersection, as this last half-plane will cause everything to be removed from the deque. To avoid this problem, we have to manually check for parallel half-planes, and if they have opposite direction, we just instantly stop the algorithm and return an empty intersection.
61+
62+
63+
Thus the only case we actually need to handle is having multiple half-planes with the same angle, and it turns out this case is fairly easy to handle: we only have keep the leftmost half-plane and erase the rest, since they will be completely redundant anyways.
6064
To sum up, the full algorithm will roughly look as follows:
6165

6266
1. We begin by sorting the set of half-planes by angle, which takes $O(N \log N)$ time.
@@ -81,7 +85,7 @@ struct Point {
8185
long double x, y;
8286
explicit Point(long double x = 0, long double y = 0) : x(x), y(y) {}
8387

84-
// Addition, substraction, multiply by constant, cross product.
88+
// Addition, substraction, multiply by constant, dot product, cross product.
8589

8690
friend Point operator + (const Point& p, const Point& q) {
8791
return Point(p.x + q.x, p.y + q.y);
@@ -94,6 +98,10 @@ struct Point {
9498
friend Point operator * (const Point& p, const long double& k) {
9599
return Point(p.x * k, p.y * k);
96100
}
101+
102+
friend long double dot(const Point& p, const Point& q) {
103+
return p.x * q.x + p.y * q.y;
104+
}
97105

98106
friend long double cross(const Point& p, const Point& q) {
99107
return p.x * q.y - p.y * q.x;
@@ -119,17 +127,10 @@ struct Halfplane {
119127
}
120128

121129
// Comparator for sorting.
122-
// If the angle of both half-planes is equal, the leftmost one should go first.
123130
bool operator < (const Halfplane& e) const {
124-
if (fabsl(angle - e.angle) < eps) return cross(pq, e.p - p) < 0;
125131
return angle < e.angle;
126132
}
127133

128-
// We use equal comparator for std::unique to easily remove parallel half-planes.
129-
bool operator == (const Halfplane& e) const {
130-
return fabsl(angle - e.angle) < eps;
131-
}
132-
133134
// Intersection point of the lines of two half-planes. It is assumed they're never parallel.
134135
friend Point inter(const Halfplane& s, const Halfplane& t) {
135136
long double alpha = cross((t.p - s.p), t.pq) / cross(s.pq, t.pq);
@@ -156,10 +157,8 @@ vector<Point> hp_intersect(vector<Halfplane>& H) {
156157
H.push_back(aux);
157158
}
158159
159-
// Sort and remove duplicates
160+
// Sort by angle and start algorithm
160161
sort(H.begin(), H.end());
161-
H.erase(unique(H.begin(), H.end()), H.end());
162-
163162
deque<Halfplane> dq;
164163
int len = 0;
165164
for(int i = 0; i < int(H.size()); i++) {
@@ -175,7 +174,21 @@ vector<Point> hp_intersect(vector<Halfplane>& H) {
175174
dq.pop_front();
176175
--len;
177176
}
178-
177+
178+
// Special case check: Parallel half-planes
179+
if (len > 0 && fabsl(cross(H[i].pq, dq[len-1].pq)) < eps) {
180+
// Opposite parallel half-planes that ended up checked against each other.
181+
if (dot(H[i].pq, dq[len-1].pq) < 0.0)
182+
return vector<Point>();
183+
184+
// Same direction half-plane: keep only the leftmost half-plane.
185+
if (H[i].out(dq[len-1].p)) {
186+
dq.pop_back();
187+
--len;
188+
}
189+
else continue;
190+
}
191+
179192
// Add new half-plane
180193
dq.push_back(H[i]);
181194
++len;
@@ -259,6 +272,7 @@ It is worth mentioning that there also exists a fairly simple randomized algorit
259272
### Harder problems
260273

261274
* [POJ - Most Distant Point from the Sea - Medium](http://poj.org/problem?id=3525)
275+
* [Baekjoon - Jeju's Island - Same as above but seemingly stronger test cases](https://www.acmicpc.net/problem/3903)
262276
* [POJ - Feng Shui - Medium](http://poj.org/problem?id=3384)
263277
* [POJ - Triathlon - Medium/hard](http://poj.org/problem?id=1755)
264278
* [DMOJ - Arrow - Medium/hard](https://dmoj.ca/problem/ccoprep3p3)

0 commit comments

Comments
 (0)