Half-plane intersection

Definition

Half-plane

A half-plane is the point set consisting of a line and one side of that line. If the line is included, it is called a closed half-plane; if the line is not included, it is called an open half-plane.

Its analytic form is generally Ax+By+C≥0Ax+By+C\ge 0.

In computational geometry, half-planes are represented by vectors. Throughout a problem, we consistently take either the left side or the right side of a vector as the half-plane.

Half-plane
Half-plane

Intersection of half-planes

A half-plane intersection is the intersection of multiple half-planes. Because a half-plane is a point set, the intersection of point sets is also a point set, forming a region in the Cartesian coordinate system.

This is much like an ordinary linear-programming problem: the resulting half-plane intersection is the feasible region in linear programming. In general, a half-plane intersection is bounded, and problems often ask us to compute its area or other quantities.

It can be understood as the intersection of the right sides of all vectors in a set, or as the solution set of the following system of equations.

{A1x+B1y+C≥0A2x+B2y+C≥0⋯\begin{cases} A_1x+B_1y+C\ge 0\\ A_2x+B_2y+C\ge 0\\ \cdots \end{cases}

Kernel of a polygon

If the segment joining a point in a point set to any point on a polygon has no other intersection with the polygon, that point set is called the kernel of the polygon.

If every edge of a polygon is regarded as a vector joined head to tail, the intersection of the half-planes on the interior side of these vectors is the kernel of the polygon.

Method - S&I algorithm

Sorting by polar angle

The C language has a library function called atan2(double y,double x), which returns θ∈(−π,π]\theta\in (-\pi,\pi], where θ=arctan⁡yx\theta =\arctan \frac{y}{x}.

Use the vectors directly as the arguments, call this function, and sort by its return value as the key to obtain a new set of edges (vectors).

When sorting, if two collinear vectors point in the same direction, keep the one closer to the feasible region. For example, if two vectors have the same polar angle and we need the half-plane to the left of the vector, we only need to retain the vector on the left. To decide which one to keep, compare an endpoint of one vector with the other and check whether it lies to the left or right.

Maintaining a monotone queue

Because a half-plane intersection is a convex polygon, we need to maintain a convex hull. A newly added vector can affect only the edge added first or the edge added last (the convex hull is connected at this point), so only the front and back elements need to be deleted. This is why a monotone queue is needed.

We traverse the vectors in sorted order and maintain another array of intersection points. When the queue contains more than 2 elements, intersections are formed between them.

For the current vector, if the previous intersection point lies on the opposite side of the half-plane represented by this vector, the preceding edge is meaningless.

Monotone queue
Monotone queue

As in the figure, suppose that we take the left half-plane of each vector. After sorting by polar angle, the traversal order should be a⃗→b⃗→c⃗\vec a\to\vec b\to\vec c. When a⃗\vec a and b⃗\vec b enter the queue, they produce a point DD in the intersection-point array (the intersection-point array stores the intersection of the vector at each queue index with the preceding vector).

When we next reach c⃗\vec c, we find that DD is to the right of c⃗\vec c. Because the polar angle of the vector that produced DD is necessarily smaller than that of c⃗\vec c, the vector that produced DD (namely b⃗\vec b) has no effect on the half-plane intersection.

Another possible situation is that, near the end, a newly added vector causes an effect starting from the front of the queue.

Effect at the front
Effect at the front

Again suppose that we take the left half-plane of each vector. After adding vector f⃗\vec f, the first intersection point GG lies to the right of f⃗\vec f. Reversing the criterion above shows that we should delete vector a⃗\vec a, namely the front vector.

Finally, use the front vector to remove redundant vectors at the back. The front vector is constrained by the later vectors, while the back vector is not. They now form a cycle, so the front vector can also constrain the back vector.

Obtaining the half-plane intersection

If the half-plane intersection is a convex nn-gon, the intersection-point array will contain nn points at the end. Connecting them head to tail gives an nn-gon with a consistent orientation (clockwise or counterclockwise).

We can then use triangulation to calculate its area. (Computing the area is the most basic type of question.)

Sometimes the half-plane intersection does not exist or has area 0, so remember to handle boundary cases.

Notes

When a vector appears that can eject all points in the queue (that is, all points in the queue lie to the right of that vector), we must process the back before the front. Therefore, in the loop, we must process the --r; part before the ++l; part. The reason is as follows.

Figure: hpi4

In the usual case, we append an edge after a queue whose order is {u⃗,v⃗}\left\{\vec{u},\vec{v}\right\} (the edge is the vector w⃗\vec w), producing an intersection point NN and shrinking the region after v⃗\vec{v}.

Figure: hpi5

However, every operation is not necessarily ordinary, so it is possible for point MM to be pushed out.

Figure: hpi6

If vector a⃗\vec a appears and MM lies to the right of a⃗\vec a, then MM must leave the queue. If we enumerate from the front with ++l, the range is obviously enlarged. In fact, point MM is jointly formed by u⃗\vec u and v⃗\vec v, so we need to consider whether u⃗\vec u or v⃗\vec v affects the current process. Since the vectors are in counterclockwise order after sorting by polar angle, v⃗\vec v has the greater effect.

As shown in the figure, if MM is confirmed to be on the right side of a⃗\vec a, then the effect of v⃗\vec v can no longer contribute anything to the answer for the half-plane intersection.

The reason we remove the front is that the current vector imposes a stronger restriction than the front vector. This condition presupposes that there are more than two line segments (vectors) in the queue; otherwise, the situation above can occur.

Therefore, the back must always be removed before the front.

Code - comparison
friend bool operator<(seg x, seg y) {
  db t1 = atan2((x.b - x.a).y, (x.b - x.a).x);
  db t2 = atan2((y.b - y.a).y, (y.b - y.a).x);  // compute the polar angle
  if (fabs(t1 - t2) > eps)                      // if the polar angles differ
    return t1 < t2;
  return (y.a - x.a) * (y.b - x.a) >
         eps;  // determine which side of vector y vector x is on; put the leftmost first
}
Code - incremental part
// pnt its(seg a,seg b) computes the intersection of segments a and b
// s[] contains the vectors sorted by polar angle
// q[] is the vector queue
// t[i] is the intersection of s[i-1] and s[i]
// [coding style] the queue range is (l,r]
// compute the half-plane on the left side of each vector
int l = 0, r = 0;
for (int i = 1; i <= n; ++i)
  if (s[i] != s[i - 1]) {
    // check the back first
    while (r - l > 1 && (s[i].b - t[r]) * (s[i].a - t[r]) >
                            eps)  // pop the back if the previous intersection is to the right of the vector
      --r;
    while (r - l > 1 && (s[i].b - t[l + 2]) * (s[i].a - t[l + 2]) >
                            eps)  // pop the front if the first intersection is to the right of the vector
      ++l;
    q[++r] = s[i];
    if (r - l > 1) t[r] = its(q[r], q[r - 1]);  // compute the new intersection
  }
while (r - l > 1 &&
       (q[l + 1].b - t[r]) * (q[l + 1].a - t[r]) > eps)  // remove redundant elements
  --r;
t[r + 1] = its(q[l + 1], q[r]);  // compute the new intersection
++r;
// note that ++r cannot be written inside t here...

Exercises

POJ 2451 Uyuw's Concert Pay attention to boundary cases.

POJ 1279 Art Gallery Find the kernel of the polygon.

CQOI2006 Convex Polygon

This content comes from OI Wiki: Half-plane intersection. See the original for authors and revision history. AIOJ has adapted the formatting, in-site links, and resource paths.

Content is shared under CC BY-SA 4.0 and SATA license; additional terms are governed by the original notice. Thanks to the OI Wiki authors and contributors; per the SATA terms, please visit the OI Wiki repository and star it to show your support.