2

I have a list of consecutive points and I need to find the coordinates of a polygon some size larger. I can calculate each of the points in the new polygon if it has convex angles, but I'm not sure how to adjust for when the angles are concave.

qw3n
  • 6,236
  • 6
  • 33
  • 62

4 Answers4

0

Concave angles can be treated in exactly the same way as convex ones: For each vertex you generate lines that are parallel to the two original segments but shifted by your offset value. Then the vertex is replaced with the intersection of these two lines.

The difficulty is that the resulting polygon can have intersections if the original one has one or more concave angles. There are different ways to handle these intersections. Generally they can produce inner contours (holes in the polygon) but maybe you are only interested in the outer contour.

In any case you have to find the intersection points first. If you don't find any, you are finished.

Otherwise find a start point of which you can be sure that it is on the outer contour. In many cases you can take the one with smallest X coordinate for that. Then trace the polygon contour until you get to the first intersection. Add the intersection to the polygon. If you are only interested in the outer contour, then skip all following vertices until you get back to the intersection point. Then continue to add the vertexes to the resulting polygon until you get to the next intersection and so on.

If you also need the inner contours (holes) it gets a bit more complicated, but I guess you can figure this out.

I also need to add that you should pe prepared for special cases like (almost) duplicate edges that cause numerical problems. Generally this is not a trivial task, so if possible, try to find a suitable polygon library.

Frank Puffer
  • 8,135
  • 2
  • 20
  • 45
0

For this problem I found a relatively simple solution for figuring out whether the calculated point was inside or outside the original polygon. Check to see whether the newly formed line intersects the original polygon's line. A formula can be found here http://www.geeksforgeeks.org/orientation-3-ordered-points/.

qw3n
  • 6,236
  • 6
  • 33
  • 62
0

Suppose your polygon is given in counter-clockwise order. Let P1=(x1,y1), P2=(x2,y2) and P3=(x3,y3) be consecutive vertices. You want to know if the angle at P2 is “concave” i.e. more than 180 degrees. Let V1=(x4,y4)=P2-P1 and V2=(x5,y5)=P3-P2. Compute the “cross product” V1 x V2 = (x4.y5-x5.y4). This is negative iff the angle is concave.

0

Here is a code in C# that receives a list of Vector2D representing the ordered points of a polygon and returns a list with the angles of each vertex. It first checks if the points are clockwise or counterclockwise, and then it loops through the points calculating the sign of the cross product (z) for each triple of angles, and compare the value of the cross product to the clockwise function result to check if the calculated angle to that point needs to be the calculated angle or adjusted to 360-angle. The IsClockwise function was obtained in this discussion: How to determine if a list of polygon points are in clockwise order?

public bool IsClockwise(List<Vector2> vertices)
{
    double sum = 0.0;
    
    for (int i = 0; i < vertices.Count; i++)
    {
        Vector2 v1 = vertices[i];
        Vector2 v2 = vertices[(i + 1) % vertices.Count];
        sum += (v2.x - v1.x) * (v2.y + v1.y);
    }

    return sum > 0.0;
}

List<float> estimatePolygonAngles(List<Vector2> vertices)
{
    if (vertices.Count < 3)
        return null;

    //1. check if the points are clockwise or counterclockwise:

    int clockwise = (IsClockwise(vertices) ? 1 : -1);

    List<float> angles = new List<float>();
    List<float> crossProductsSigns = new List<float>();
    Vector2 v1, v2;

    //2. calculate the angles between each triple of vertices (first and last angles are computed separetely because index of the array):

    v1 = vertices[vertices.Count - 1] - vertices[0];
    v2 = vertices[1] - vertices[0];
    angles.Add(Vector2.Angle(v1, v2));
    crossProductsSigns.Add(Vector3.Cross(v1, v2).z > 0 ? 1 : -1);

    for (int i = 1; i < vertices.Count-1; i++)
    {
        v1 = vertices[i-1] - vertices[i];
        v2 = vertices[i+1] - vertices[i];
        angles.Add(Vector2.Angle(v1, v2));
        crossProductsSigns.Add(Vector3.Cross(v1, v2).z > 0 ? 1 : -1);
    }
    
    v1 = vertices[vertices.Count - 2] - vertices[vertices.Count - 1];
    v2 = vertices[0] - vertices[vertices.Count - 1];
    angles.Add(Vector2.Angle(v1, v2));
    crossProductsSigns.Add(Vector3.Cross(v1, v2).z > 0 ? 1 : -1);

    //3. for each computed angle, check if the cross product is the same as the as the direction provided by the clockwise function, if dont, the angle must be adjusted to 360-angle

    for (int i = 0; i < vertices.Count; i++)
    {
        if (crossProductsSigns[i] != clockwise)
            angles[i] = 360.0f - angles[i];
    }

    return angles;
}
Lks
  • 1
  • 2