|
| 1 | +<!--?title Minkowski sum of convex polygons --> |
| 2 | +# Minkowski sum of convex polygons |
| 3 | + |
| 4 | +## Definition |
| 5 | +Consider two sets $A$ and $B$ of points on a plane. Minkowski sum $A + B$ is defined as $\\{a + b| a \in A, b \in B\\}$. |
| 6 | +Here we will consider the case when $A$ and $B$ consist of convex polygons $P$ and $Q$ with their interiors. |
| 7 | +Throughout this article we will identify polygons with ordered sequences of their vertices, so that notation like $|P|$ or |
| 8 | +$P_i$ makes sense. |
| 9 | +It turns out that the sum of convex polygons $P$ and $Q$ is a convex polygon with at most $|P| + |Q|$ vertices. |
| 10 | + |
| 11 | +## Algorithm |
| 12 | + |
| 13 | +Here we consider the polygons to be cyclically enumerated, i. e. $P_{|P|} = P_0,\ Q_{|Q|} = Q_0$ and so on. |
| 14 | + |
| 15 | +Since the size of the sum is linear in terms of the sizes of initial polygons, we should aim at finding a linear-time algorithm. |
| 16 | +Suppose that both polygons are ordered counter-clockwise. Consider sequences of edges $\\{\overrightarrow{P_iP_{i+1}}\\}$ |
| 17 | +and $\\{\overrightarrow{Q_jQ_{j+1}}\\}$ ordered by polar angle. We claim that the sequence of edges of $P + Q$ can be obtained by merging |
| 18 | +these two sequences preserving polar angle order and replacing consequitive co-directed vectors with their sum. Straightforward usage of this idea results |
| 19 | +in a linear-time algorithm, however, restoring the vertices of $P + Q$ from the sequence of sides requires repeated addition of vectors, |
| 20 | +which may introduce unwanted precision issues if we're working with floating-point coordinates, so we will describe a slight |
| 21 | +modification of this idea. |
| 22 | + |
| 23 | + |
| 24 | +Firstly we should reorder the vertices in such a way that the first vertex |
| 25 | +of each polygon has the lowest y-coordinate (in case of several such vertices pick the one with the smallest x-coordinate). After that the sides of both polygons |
| 26 | +will become sorted by polar angle, so there is no need to sort them manually. |
| 27 | +Now we create two pointers $i$ (pointing to a vertex of $P$) and $j$ (pointing to a vertex of $Q$), both initially set to 0. |
| 28 | +We repeat the following steps while $i < |P|$ or $j < |Q|$. |
| 29 | + |
| 30 | +1. Append $P_i + Q_j$ to $P + Q$. |
| 31 | + |
| 32 | +2. Compare polar angles of $\overrightarrow{P_iP_{i + 1}}$ and $\overrightarrow{Q_jQ_{j+1}}$. |
| 33 | + |
| 34 | +3. Increment the pointer which corresponds to the smallest angle (if the angles are equal, increment both). |
| 35 | + |
| 36 | +## Visualization |
| 37 | + |
| 38 | +Here is a nice visualization, which may help you understand what is going on. |
| 39 | + |
| 40 | +<center></center> |
| 41 | + |
| 42 | +## Distance between two polygons |
| 43 | +One of the most common applications of Minkowski sum is computing the distance between two convex polygons (or simply checking whether they intersect). |
| 44 | +The distance between two convex polygons $P$ and $Q$ is defined as $\min\limits_{a \in P, b \in Q} ||a - b||$. One can note that |
| 45 | +the distance is always attained between two vertices or a vertex and an edge, so we can easily find the distance in $O(|P||Q|)$. However, |
| 46 | +with clever usage of Minkowski sum we can reduce the complexity to $O(|P| + |Q|)$. |
| 47 | + |
| 48 | +If we reflect $Q$ through the point $(0, 0)$ obtaining polygon $-Q$, the problem boils down to finding the smallest distance between a point in |
| 49 | +$P + (-Q)$ and $(0, 0)$. We can find that distance in linear time using the following idea. |
| 50 | +If $(0, 0)$ is inside or on the boundary of polygon, the distance is $0$, otherwise the distance is attained between $(0, 0)$ and some vertex or edge of the polygon. |
| 51 | +Since Minkowski sum can be computed |
| 52 | +in linear time, we obtain a linear-time algorithm for finding the distance between two convex polygons. |
| 53 | + |
| 54 | +## Implementation |
| 55 | +Below is the implementation of Minkowski sum for polygons with integer points. Note that in this case all computations can be done in integers since |
| 56 | +instead of computing polar angles and directly comparing them we can look at the sign of cross product of two vectors. |
| 57 | + |
| 58 | +```cpp minkowski |
| 59 | +struct pt{ |
| 60 | + long long x, y; |
| 61 | + pt operator + (const pt & p) const { |
| 62 | + return pt{x + p.x, y + p.y}; |
| 63 | + } |
| 64 | + pt operator - (const pt & p) const { |
| 65 | + return pt{x - p.x, y - p.y}; |
| 66 | + } |
| 67 | + long long cross(const pt & p) const { |
| 68 | + return x * p.y - y * p.x; |
| 69 | + } |
| 70 | +}; |
| 71 | + |
| 72 | +void reorder_polygon(vector<pt> & P){ |
| 73 | + size_t pos = 0; |
| 74 | + for(size_t i = 1; i < P.size(); i++){ |
| 75 | + if(P[i].y < P[pos].y || (P[i].y == P[pos].y && P[i].x < P[pos].x)) |
| 76 | + pos = i; |
| 77 | + } |
| 78 | + rotate(P.begin(), P.begin() + pos, P.end()); |
| 79 | +} |
| 80 | + |
| 81 | +vector<pt> minkowski(vector<pt> P, vector<pt> Q){ |
| 82 | + // the first vertex must be the lowest |
| 83 | + reorder_polygon(P); |
| 84 | + reorder_polygon(Q); |
| 85 | + // we must ensure cyclic indexing |
| 86 | + P.push_back(P[0]); |
| 87 | + P.push_back(P[1]); |
| 88 | + Q.push_back(Q[0]); |
| 89 | + Q.push_back(Q[1]); |
| 90 | + // main part |
| 91 | + vector<pt> result; |
| 92 | + size_t i = 0, j = 0; |
| 93 | + while(i < P.size() - 2 || j < Q.size() - 2){ |
| 94 | + result.push_back(P[i] + Q[j]); |
| 95 | + auto cross = (P[i + 1] - P[i]).cross(Q[j + 1] - Q[j]); |
| 96 | + if(cross >= 0) |
| 97 | + ++i; |
| 98 | + if(cross <= 0) |
| 99 | + ++j; |
| 100 | + } |
| 101 | + return result; |
| 102 | +} |
| 103 | + |
| 104 | +``` |
| 105 | +
|
| 106 | +## Problems |
| 107 | + * [Codeforces 87E Mogohu-Rea Idol](https://codeforces.com/problemset/problem/87/E) |
| 108 | + * [Codeforces 1195F Geometers Anonymous Club](https://codeforces.com/contest/1195/problem/F) |
| 109 | + * [TIMUS 1894 Non-Flying Weather](https://acm.timus.ru/problem.aspx?space=1&num=1894) |
0 commit comments