Does anyone know an equation to calculate the length to the edge of a regular polygon from the centre based on the angle?

Wondering if anyone can help with an equation to find the length to the perimeter of a polygon from any angle?
Here is an example of the test setup I have so far:


public class myPolygonScreen : MonoBehaviour
{

private Vector3 screenCentre;

public int polyRadius;
public int polyPoints;
public float angle;

void Awake()
{

screenCentre = new Vector3(Screen.width, Screen.height, 0) / 2;

}

void FixedUpdate()
{
float inRadius = Mathf.Cos(polyRadius);
float lengthAtAngle = polyRadius;
this.transform.position = screenCentre - (new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0) * lengthAtAngle);

angle = Time.time * Time.fixedDeltaTime * 50;
}
}


What I’d like to do is have the sprite move around the perimeter of a polygon rather than in a circle, but I’m struggling with the equation to subtract the distance from the centre of the screen based on the angle and number of polygon points.

Well, here you go:

public static float GetRadiusOfRegularPoly(float aRadius, int aSegments, float aAngle)
{
    float a = Mathf.PI / aSegments;                     // half segment angle
    float h = aRadius * Mathf.Sin(Mathf.PI * 0.5f - a); // height of the triangle
    float a2 = a - Mathf.PingPong(aAngle, a);           // angle inside current triangle
    return h / Mathf.Sin(Mathf.PI * 0.5f - a2);
}

It will calculate the required radius for a certain angle. If can be used like this:

public static Vector2 GetPointOnPolyPerimeter(Vector2 aCenter, float aRadius, int aSegments, float aAngle)
{
    float r = GetRadiusOfRegularPoly(aRadius, aSegments, aAngle);
    var d = new Vector2(Mathf.Cos(aAngle)*r, Mathf.Sin(aAngle)*r);
    return aCenter + d;
}

However this has several issues. First of all it might not be that numerical stable to calculate the required radius based on the angle. So the resulting path might have a slight jitter but probably small enough so you wouldn’t notice.

Though the slightly bigger issue is that since you want to move based on the angle with a constant angular velocity you would get a changing linear movement speed along the perimeter. You get the highest speed at the corners of the polygon and the slowest speed at the center of each edge. With a higher segment count this effect gets smaller. However for relatively small segment counts it’s quite a bit. The easiest case to calculate would be a segment count of 4 (essentially a square). The diagonal is 1.414 times larger than the height of each triangle. So at the corners you would move about 40% faster than at the center of an edge.

So it would be better to just calculate the corner points of your polygon, store them in an array and just lerp between the corners. Like this:

public static Vector2 GetPointOnPolyPerimeter(Vector2 aCenter, float aRadius, int aSegments, float t)
{
    float a = t * aSegments;
    float a1 = Mathf.PI * 2 * Mathf.Floor(a) / aSegments;
    float a2 = Mathf.PI * 2 * Mathf.Ceil(a) / aSegments;
    float f = a % 1;
    var p1 = new Vector2(Mathf.Cos(a1), Mathf.Sin(a1));
    var p2 = new Vector2(Mathf.Cos(a2), Mathf.Sin(a2));
    var d = Vector2.Lerp(p1, p2, f) * aRadius;
    return aCenter + d;
}

Note in this case the “t” parameter is simple a value between 0 and 1 which is essentially a “normalized” distance along the perimeter. So when slowly increasing t from 0 to 1 you will have completed one trip around the perimeter.

Just to explain what’s happening here:

a1 and a2 are the start and end angle of the current triangle. “f” is the normalized value along the edge of the current triangle. p1 and p2 are simply the corner points of the current triangle. In the end we simply lerp between the two points to get the intermediate point. I multiply by the radius at the end to avoid unnecessary multiplications.