The Weiler-Atherton clipping algorithm is a general purpose 2D clipping algorithm for clipping any simple polygon against any other simple polygon for something like shadow rendering. The polygons can be convex or concave, they can even have holes (though this visualization doesn't support this aspect of the algorithm). Within this discussion (and through out the tool) we will refer to the polygon being used as the clip region as the Clip polygon and the polygon being clipped as the Subject polygon.
The primary data structure for this algorithm is a list of points that represents each polygon. The list contains a traversal of the polygon around its edges. The only requirement is that the polygons are both specified in the same order. This particular implementation requires that the points be ordered in the counter-clockwise direction, but the algorithm could easily be adjusted to use clockwise specification.
There are two distinct phases to this algorithm: finding the intersection points and identifying the clipped regions. We will discuss each of these separately.
In this phase of the algorithm every edge of the Subject polygon needs to be checked against every edge of the Clip polygon to see if the two intersect. While there are several ways to find the intersection between two lines, a particularly convenient technique is to use the parametric representations of the two line segments that are being compared.
Given two points, A and B, the parametric equation for the line containing them is P(t) = A + bt, where b is the vector B-A and t is the parametric variable. When t = 0, P(t) is A and when t=1, P(t) = B. Similarly, for a second set of points Cc and D, we could write Q(u) = C + du, where d = D-C. The point where these two lines intersect is then the moment when A+bt = C+du. As this equation has two variables, we need to simplify to get rid of one of them. If we define c = C - A, we can rewrite this equation as bt = c+du.
To get rid of the u term, we are going to take advantage of one of the properties of the dot product - the dot product of a vector and a vector perpendicular to it is zero. In 2D, finding a perpendicular vector is very simple. Given some vector v =(x,y), there is a special vector called the perp vector v⊥ = (-y,x), which is guaranteed to be perpendicular to v. We are going to take the perp of d, d⊥, and apply the dot product of it to both side of the equation:
If we solve for t and plug it back into A+bt, we will have the point where these two lines intersect.
There are, of course, some subtleties to consider. What happens when d⊥•b = 0? In this case, the two lines are parallel (how do we know that?) and they will never intersect. If this value is non-zero, there is an intersection point, but it is not necessarily within the two line segments. To check if the point is between A and B, we merely have to check if t is between the values 0 and 1. Similarly, we can calculate u and check if it is also between 0 and 1. If both of these conditions are met, then this intersection point is a real intersection between the two polygons. This point is then inserted into both point lists in the appropriate position in the list.
An important attribute of an intersection point is whether or not it is an inbound intersection. That is to say, while traversing the Subject polygon in the specified order, does this intersection mark the point when the line being followed enters the Clip polygon? Fortunately, this is simple to derive based on values that have already been calculated. Due to the choice in direction, d⊥ is an outward facing perpendicular. Another property of the dot product is that if the angle between the two vectors is greater than 90°, the sign of the dot product is negative. The vector b is the vector along the edge AB that points in the direction of B. If the angle between b and d⊥ > 90 that means that b must be an inbound vector, and thus our intersection point is an inbound intersection. Of course,d⊥•b was already calculated, so we just look at the sign to tell if this intersection is inbound.
Once the intersections have been found, it is relatively easy to clip the Subject polygon. We start with the Subject polygon list and start traversing it until we find an inbound intersection that has not been visited. This will be the first point of a clipped polygon, so we save it and mark it as visited. We then continue to follow the list, saving each point and marking it as visited. When another intersection point is encountered, continuing to follow the Subject list would mean that we would exit the polygon. So instead, we switch lists. As the intersection point exists in both lists, we jump to the same point in the Clip list and continue to traverse the point list, still saving the points and marking them as visited. Eventually, swapping point lists at every intersection, we will return to the initial inbound intersection (we know because it is marked visited). The list of points we have been saving can now be saved as a complete polygon. As the two original polygons can be concave, it is possible that there is more than one clipped polygon, so we must find the rest of them. As we are back were we started in the Subject polygon list where we started, we can return to the first step of this phase - traversing the point list looking for an unvisited inbound intersection. When the end of the point list is reached, all of the new clipped polygons have been identified and the algorithm is done.
There is a simple optimization that can be made to this algorithm. Rather than traversing the whole polygon, a third list containing just the inbound intersections can be kept. Using this list, the algorithm can jump immediately to the next unvisited inbound intersection, and the process is complete when there are no longer any unvisited points in the list. This tool doesn't use this optimization in order to make the process clearer.
Another consideration we have to make is the eventuality that there are no intersections between the two polygons. If this happens, there are three possible causes:
In the first case, the resulting clipped polygon is just the Subject polygon. In the second case, the resulting clipped polygon would be a copy of the Clip polygon. In the third case, no polygons will be returned.