I'm have some vertices of a polygon with labels on them. I want to place the labels so that they are always on the outside of the polygon. So in the image above, all of the labels are fine except for #3 and #4, which I want to be on the bottom, outside of the polygon. So generally, how do I determine, for a particular vertex, how to offset it such that it's outside the polygon?
-
Is it guaranteed that the polygon is simple (does not intersect itself)? (If not, the "inside" of the polygon is not a simple question.) Is it guaranteed that the interior angles of the polygon are less than 180°? (If so, there is an easier answer.) Do you need the entire label to be outside the polygon, or could just the center be inside with the polygon possibly cutting across part of the label? (If it all must be outside, the routine would also need details on the size of the label.) – Rory Daulton Jun 18 '19 at 20:25
-
You can build outer offset points as [described here](https://stackoverflow.com/questions/52420003/how-to-extend-the-polygon-to-a-certain-distance/52420254#52420254) – MBo Jun 19 '19 at 03:45
3 Answers
Since you do not show any code of your own, I will just state some ideas. If you want more details including code, show more effort of your own then ask.
I'll assume here that the polygon is assumed to be a simple polygon--one that does not intersect itself. If a polygon does intersect itself, the definition of its "inside" is not so straightforward and there are multiple definitions of the inside. I will not assume that the polygon is convex--all the interior angles are less than 180°. (That would allow an easier answer.) I'll also assume that you want the center of your label to be outside the polygon but will allow a corner or small part of the label to be inside.
First, traverse the polygon and find its "winding angle," the amount the direction angle changes during the traversal. If the polygon is simple, the angle will be either +180° or -180°. One of those means you traversed the polygon clockwise, the other one means counter-clockwise. (Which is which depends on your coordinate system: Cartesian or graphing or other.)
Then traverse the polygon again. Now that you know the direction of the polygon, at each vertex you can find whether the exterior angle goes clockwise or counterclockwise from the entering segment. Find that direction and the size of the angle, then move half that angle in that direction. Move a given distance from the vertex along that angle, and you have the position of the center of your label.
That should work well for the vast majority of polygons. In some edge cases for non-convex polygons, that location moved away from the polygon into another part of the polygon. You then reduce the distance the label is from its vertex until the label moves back into the polygon's outside.
I gave an answer to a related question: How do I efficiently determine if a polygon is convex, non-convex or complex?.

- 21,934
- 6
- 42
- 50
On every vertex, the incoming and outgoing edges form an angle that covers some sector. You can place the label at some distance along the bisector of this angle. You find the direction vector of the bisector by adding two unit vectors originating from the vertex in the directions of the edges.
Finding the correct bisector side requires some care. In the first place, you need to orient the polygon, i.e. check if it is clockwise or counterclockwise. This is simply done by computing the area with the shoelace formula and testing the sign.
Then, if I am right, you can test the area of triangle formed by the two edges and compare its sign to that of the whole polygon. This tells you if the angle is convex or reflex, and you know the proper side. For a convex polygon, the side is always negative for a vector computed as above.
Maybe follow something like this: First, make sure the polygon does not self-intersect, see the previous answers. Then, let the polygon be counter-clockwise oriented and represented by an array (a 2 by n+2 matrix) of its vertices (the vertices are traversed in counter-clockwise order)
double P[n+2][2] = {{pxn, pyn}, {px1, py1}, {px2, py2}, ..., {pxn, pyn}, {px1, py1}};
double Label_position[n][2];
void generate_labels(const double (&P)[n+2][2], double (&Label_position)[n][2]){
double v1[2];
double v2[2];
for(j = 1, j <= n, j = j+1) {
v1[0] = P[j][0] - P[j-1][0];
v1[1] = P[j][1] - P[j-1][1];
v2[0] = P[j+1][0] - P[j][0];
v2[1] = P[j+1][1] - P[j][1];
v1 = normalize(v1);
v2 = normalize(v2);
t = add_vectors(v1, v2);
t = normalize(t);
Label_position[j][0] = t[1] + P[j][0];
Label_position[j][1] = - t[0] + P[j][1];
}
}
This function generates the coordinates of the points at the tips of the unit angle bisector vectors pointing in the exterior of the polygon (see Yves Daoust's answer and the picture he has generated).

- 40,271
- 12
- 71
- 104

- 1,874
- 2
- 7
- 9
-
You didn't correctly implement the solution, you didn't care about orientation. – Jun 20 '19 at 09:44
-
@YvesDaoust As I said in my answer, I assume that the polygon is not self-intersecting and is given by an array of vertices, ordered consecutively following a counter-clockwise orientation. With these conditions imposed on the input data, the routine generates the tips of the unit bisectors pointing outwards. I do not claim to be solving the problem in its full generality, just trying to help in case the person has a reasonable (which is quite likely, by looking at the picture of a convex polygon provided) situation at hand and doesn't need all possible complicated scenarios. – Futurologist Jun 20 '19 at 16:49
-
@YvesDaoust Do you have a counter example, where this doesn't work? I just want to see where I made a mistake. And I mean a counter example where the input restrictions are respected, so no self intersecting polygon or vertices ordered in some random order. – Futurologist Jun 20 '19 at 16:50
-
-
(for a counterexample, consider a dart... https://proofwiki.org/wiki/Definition:Quadrilateral/Dart ) – Sneftel Jul 21 '19 at 17:53
-
@Sneftel Where do I assume the polygon to be "convex"? What I said, in my comment, is that the picture provided in the original question is of a convex polygon, which makes me think that the person asking does not deal with self-intersecting polygons. – Futurologist Jul 21 '19 at 22:02
-
-
@Sneftel No it does not. It works for non-convex, non-intersecting polygons. My test cases were non-convex. – Futurologist Jul 21 '19 at 22:05
-
Ah, I see now... I misread your code and thought you were doing the perp before the bisection, rather than afterwards. – Sneftel Jul 22 '19 at 08:09
-
@Sneftel Thank you for correcting the down-votes. My intention was to suggest a piece of an algorithm that could be helpful in working on this problem, not to solve it in its full generality, which might be too complicated and time-consuming especially if it looks like the person asking might not be considering self-intersecting polygons. – Futurologist Jul 23 '19 at 14:32