Drawing circles with triangles
I can suggest a bit of math trickiness here. I highly doubt that would improve the readability of your code, but these reduce the amount of required computations. And one remark, I haven't worked with Python, so, no code. Sorry about that. Only performance suggestions.

Keep your angles constant

The heaviest part you have in your vertex computation is constantly recomputing sine and cosine, as you're creating a circle by "rotating the radius" and its angle is constantly changing by a fixed value.

You can reduce this to computing only a single pair of sine and cosine by relying on the rotation matrix. Once computed, it allows you to rotate an arbitrary point around zero by a constant angle.

You push in the first "radius" yourself, then you rotate it by rad, then by 2*rad (and you're forced to compute its sine and cosine again) and so on. But you don't really need it! Instead, you can take the previous computed radius and rotate it by rad again, using the same sine and cosine. The math looks like:

x_new = x * cos(rad) - y * sin(rad)
y_new = x * sin(rad) + y * cos(rad)


There's only one thing to be cautious of: floating point isn't perfect and absolutely precise. And in extreme cases the error will add up with each iteration and may become noticeable. You can't really counter that in any way but reducing the number of iterations. And yes, you can do that too.

Exploit your axes

You have 2 orthogonal axes. And you're drawing a circle which has a neat property of having all the points within a specific distance from its center. Assuming the circle is centered at (0; 0) for brevity, how many points can you get by performing a single rotation? One? No, actually eight. Here are 3 independent things you can do with a single point to get some others, each doubles the amount of points you get:


Negate X
Negate Y
Swap X and Y



  1 * 2 * 2 * 2 == 8 # Yeah, okay.


Imagine you're traversing the circle only knowing 1/8th of its points.


You start from angle 0 (right), you reach pi/4 and...
You follow your pointset in reverse with coordinates swapped, until you reach pi/2.
You swap coordinates back, negate X and follow the pointset straight again, you reach 3pi/4.
You swap coordinates and follow the pointset in reverse again until you reach pi.
You swap coordinates, negate Y and traverse the lower semicircle the same way as above.


So it makes sense to only compute 1/8th of the circle, points in [0; pi/4]. This takes 8 times less point computations, but you should store the results and reuse them when drawing the circle. This requires some extra memory.

Of course, this does not relieve you of benchmarking the improvement. The above is math, just theory.