39

I am writing a program in which I need to draw polygons of an arbitrary number of sides, each one being translated by a given formula which changes dynamically. There is some rather interesting mathematics involved but I am stuck on this probelm.

How can I calculate the coordinates of the vertices of a regular polygon (one in which all angles are equal), given only the number of sides, and ideally (but not neccessarily) having the origin at the centre?

For example: a hexagon might have the following points (all are floats):

( 1.5  ,  0.5 *Math.Sqrt(3) )
( 0    ,  1   *Math.Sqrt(3) )
(-1.5  ,  0.5 *Math.Sqrt(3) )
(-1.5  , -0.5 *Math.Sqrt(3) )
( 0    , -1   *Math.Sqrt(3) )
( 1.5  , -0.5 *Math.Sqrt(3) )

My method looks like this:

void InitPolygonVertexCoords(RegularPolygon poly)

and the coordinates need to be added to this (or something similar, like a list):

Point[] _polygonVertexPoints;

I'm interested mainly in the algorithm here but examples in C# would be useful. I don't even know where to start. How should I implement it? Is it even possible?!

Thank you.

Nobody
  • 4,731
  • 7
  • 36
  • 65

7 Answers7

74
for (i = 0; i < n; i++) {
  printf("%f %f\n",r * Math.cos(2 * Math.PI * i / n), r * Math.sin(2 * Math.PI * i / n));
}

where r is the radius of the circumsribing circle. Sorry for the wrong language No Habla C#.

Basically the angle between any two vertices is 2 pi / n and all the vertices are at distance r from the origin.

EDIT: If you want to have the center somewher other than the origin, say at (x,y)

for (i = 0; i < n; i++) {
  printf("%f %f\n",x + r * Math.cos(2 * Math.PI * i / n), y + r * Math.sin(2 * Math.PI * i / n));
}
deinst
  • 18,402
  • 3
  • 47
  • 45
  • 3
    To generalize, I'd add XC and YC (the coordinates of the circle's center) and the angle of the 1st vertex A to the cos/sin terms: px = xc + r * cos(2 * pi * i / n + A); py = yc + r * sin(2 * pi * i / n + A); – ysap Aug 08 '10 at 23:27
  • Wow I didnt expect an answer so quickly. OK, so r is the distance from the origin to any of the vertices, right? And I assume n is the number of sides. I think I get this... Thanks - top notch answer :-) – Nobody Aug 08 '10 at 23:29
  • @dentist - he said "not necessarily" – ysap Aug 08 '10 at 23:30
  • 2
    @rmx: Well, it's a Math problem, not a programming one. I guess you know the equation of a circle is `x^2 + y^2 = r^2`. However, to make it into a program, you have to separate `x` and `y`. This parametric equation does this: `{ x = r * cos(theta), y = r * sin(theta), where 0 <= theta < 2 * PI }`. To make an n-side polygon, just assign n different values to theta. To make regular polygons, just do 2 * PI / n * i, where 0 <= i < n. Please refer to [Parametric equation - Wikipedia](http://en.wikipedia.org/wiki/Parametric_equation) for more information. – Siu Ching Pong -Asuka Kenji- Aug 09 '10 at 10:17
  • Thanks Asuka - I have it working very nicely now. I used this method with `double circumcircleRadius = (poly.SideLength / Math.Sin(angle)) / 2;` to get the value of r. It's actually far easier than it first seemed. – Nobody Aug 09 '10 at 11:32
  • What about if you wanted a specific rotation within a 2d coordinate space? Ie, instead of just spitting out coordinates given a number of sides and a radius, do the same, given the same + a rotation value. – Alexander Ryan Baggett Jan 28 '15 at 09:45
25

The number of points equals the number of sides.

The angle you need is angle = 2 * pi / numPoints.

Then starting vertically above the origin with the size of the polygon being given by radius:

for (int i = 0; i < numPoints; i++)
{
    x = centreX + radius * sin(i * angle);
    y = centreY + radius * cos(i * angle);
}

If your centre is the origin then simply ignore the centreX and centreY terms as they'll be 0,0.

Swapping the cos and sin over will point the first point horizontally to the right of the origin.

ChrisF
  • 134,786
  • 31
  • 255
  • 325
2

Sorry, I dont have a full solution at hand right now, but you should try looking for 2D-Rendering of Circles. All classic implementations of circle(x,y,r) use a polygon like you described for drawing (but with 50+ sides).

Rock
  • 1,216
  • 2
  • 12
  • 20
2

Say the distance of the vertices to the origin is 1. And say (1, 0) is always a coordinate of the polygon.

Given the number of vertices (say n), the rotation angle required to position the (1, 0) to the next coordinate would be (360/n).

The computation required here is to rotate the coordinates. Here is what it is; Rotation Matrix.

Say theta = 360/n;

[cos(theta) -sin(theta)]
[sin(theta) cos(theta)]

would be your rotation matrix.

If you know linear algebra you already know what i mean. If dont just have a look at Matrix Multiplication

tafa
  • 7,146
  • 3
  • 36
  • 40
1

One possible implementation to generate a set of coordinates for regular polygon is to:

Define polygon center, radius and first vertex1.
Rotate the vertex n-times2 at an angle of: 360/n.

In this implementation I use a vector to store the generated coordinates and a recursive function to generate them:

void generateRegularPolygon(vector<Point>& v, Point& center, int sidesNumber, int radius){
    // converted to radians
    double angRads = 2 * PI / double(sidesNumber);
    // first vertex  
    Point initial(center.x, center.y - radius);
    rotateCoordinate(v, center, initial, angRads, sidesNumber);
}

where:

void rotateCoordinate(vector<Point>& v, Point& axisOfRotation, Point& initial, double angRads, int numberOfRotations){
    // base case: number of transformations < 0
    if(numberOfRotations <= 0) return;
    else{
        // apply rotation to: initial, around pivot point: axisOfRotation
        double x = cos(angRads) * (initial.x - axisOfRotation.x) - sin(angRads) * (initial.y - axisOfRotation.y) + axisOfRotation.x;
        double y = sin(angRads) * (initial.x - axisOfRotation.x) + cos(angRads) * (initial.y - axisOfRotation.y) + axisOfRotation.y;
        // store the result
        v.push_back(Point(x, y));
        rotateCoordinate(v, axisOfRotation, Point(x,y), angRads, --numberOfRotations);
    }
}

Note:

Point is a simple class to wrap the coordinate into single data structure:

class Point{
public:
    Point(): x(0), y(0){ }
    Point(int xx, int yy): x(xx), y(yy) { }
private:
    int x;
    int y; 
}; 

1 in terms of (relative to) the center, radius. In my case the first vertex is translated from the centre up horizontally by the radius lenght.

2 n-regular polygon has n vertices.

Ziezi
  • 6,375
  • 3
  • 39
  • 49
0

hmm if you test all the versions that are listed here you'll see that the implementation is not good. you can check the distance from the center to each generated point of the polygon with : http://www.movable-type.co.uk/scripts/latlong.html

Now i have searched a lot and i could not find any good implementation for calculating a polyogon using the center and the radius...so i went back to the math book and tried to implement it myself. In the end i came up with this...wich is 100% good:

            List<double[]> coordinates = new List<double[]>();
            #region create Polygon Coordinates
            if (!string.IsNullOrWhiteSpace(bus.Latitude) && !string.IsNullOrWhiteSpace(bus.Longitude) && !string.IsNullOrWhiteSpace(bus.ListingRadius))
            {
                double lat = DegreeToRadian(Double.Parse(bus.Latitude));
                double lon = DegreeToRadian(Double.Parse(bus.Longitude));
                double dist = Double.Parse(bus.ListingRadius);
                double angle = 36;

                for (double i = 0; i <= 360; i += angle)
                {
                    var bearing = DegreeToRadian(i);

                    var lat2 = Math.Asin(Math.Sin(lat) * Math.Cos(dist / earthRadius) + Math.Cos(lat) * Math.Sin(dist / earthRadius) * Math.Cos(bearing));
                    var lon2 = lon + Math.Atan2(Math.Sin(bearing) * Math.Sin(dist / earthRadius) * Math.Cos(lat),Math.Cos(dist / earthRadius) - Math.Sin(lat) * Math.Sin(lat2));

                    coordinates.Add(new double[] { RadianToDegree(lat2), RadianToDegree(lon2) });

                }

                poly.Coordinates = new[] { coordinates.ToArray() };
            }
            #endregion

If you test this you'll see that all the points are at the exact distance that you give ( radius ). Also don't forget to declare the earthRadius.

private const double earthRadius = 6371.01;

This calculates the coordinates of a decagon. You see the angle used is 36 degrees. You can split 360 degrees to any number of sides that you want and put the result in the angle variable. Anyway .. i hope this helps you @rmx!

danvasiloiu
  • 751
  • 7
  • 24
0

The simple method is: Let's take N-gone(number of sides) and length of side L. The angle will be T = 360/N. Let's say one vertices is located on origin.

* First vertex = (0,0)
* Second vertex = (LcosT,LsinT)
* Third vertex = (LcosT+Lcos2T, LsinT+Lsin2T)
* Fourth vertex = (LcosT+Lcos2T+Lcos3T, LsinT+Lsin2T+Lsin3T)

You can do in for loop

danvasiloiu
  • 751
  • 7
  • 24
samir
  • 21