Say we have N
number of 3D card-shaped planes circling around a central origin, facing the middle.
To calculate the locations of these planes (relative to origin), we use the following:
auto Delta = FMath::DegreesToRadians(360.f) / (float)(N);
for (unsigned i = 0; i < N; i++) {
auto X = Radius * FMath::Sin(Delta * (float)i);
auto Y = Radius * FMath::Cos(Delta * (float)i);
auto Location = FVector(X, Y, 0.f);
// Spawn plane actor, set it's location, etc...
}
This works well. But now, let's say we want to ONLY specify N
, and use it to calculate Radius
so that the sides of each plane are barely touching, but not colliding. What we need is a way to calculate the minimum radius.
I realize I could just start at some high value, spawn in some actors, check if they are colliding, and if they aren't, then remove all actors and reduce Radius
by some value and then start again until we hit a collision, but this seems like overkill. There must be a simpler, more mathematical approach.
Any ideas? Here's an image to help visualize what I'm trying to calculate, given ONLY n
(number of sides) and a
(width of side):
Note that n = 6
and a = 10
are only figurative examples. They could be any non-zero value.
Just divide the polygon into same-size triangles (pizza slices) and calculate the central angle for one of the triangles (Delta
). Given the length of triangle base (the perimiter side) a
, use this angle to calculate the height of triangle. The height is equal to the radius.
auto radius = a / FMath::Tan(Delta / 2.0);
To calculate coordinates for the middle point of each "side" simply use polar coordinates:
E.g.:
for (unsigned i = 0; i < N; i++) {
/* ... */
auto x = radius * FMath::Cos(i * Delta + Delta / 2.0);
auto y = radius * FMath::Sin(i * Delta + Delta / 2.0);
}