Вычислить координаты вершин правильного многоугольника

Я пишу программу, в которой нужно рисовать многоугольники с произвольным числом сторон, каждая из которых переводится по заданной формуле, которая динамически изменяется. Есть довольно интересная математика, но я застрял на этом пробелме.

как вычислить координаты вершин правильного многоугольника (одного, в котором все углы равны),учитывая только количество сторон, и идеально (но не обязательно) иметь начало на центр?

например: шестиугольник может иметь следующие пункты (все 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) )

мой метод выглядит так:

void InitPolygonVertexCoords(RegularPolygon poly)

и координаты должны быть добавлены к этому (или что-то подобное, как список):

Point[] _polygonVertexPoints;

меня интересует в основном алгоритм здесь, но примеры в C# были бы полезны. Я даже не знаю с чего начать. как я должен это реализовать? Это вообще возможно?!

спасибо вы.

7 ответов


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));
}

здесь r - радиус окружности. Извините за неправильный язык нет Habla C#.

в основном угол между любыми двумя вершинами составляет 2 pi / n и все вершины находятся на расстоянии r от происхождения.

EDIT: Если вы хотите иметь центр где-то, кроме начала координат, скажите:(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));
}

количество точек равно количеству сторон.

угол, который вам нужен, это angle = 2 * pi / numPoints.

затем, начиная вертикально над началом координат с размером многоугольника, заданного radius:

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

если ваш центр является источником, просто игнорируйте centreX и centreY термины, как они будут 0,0.

обмен cos и sin over укажет первую точку горизонтально справа от начала координат.


Извините, у меня сейчас нет полного решения, но вы должны попробовать найти 2D-рендеринг кругов. Все классические реализации круга (x,y, r) используют полигон, как вы описали для рисования (но с 50+ сторонами).


скажем, расстояние вершин до начала координат равно 1. И скажем (1, 0) всегда является координатой многоугольника.

учитывая количество вершин (скажем, n), угол поворота, необходимый для расположения (1, 0) к следующей координате, будет (360/n).

вычисление, необходимое здесь, чтобы повернуть координаты. Вот что это:Матрица Поворота.

скажем тета = 360/n;

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

будет твой поворот матрица.

Если вы знаете линейную алгебру, вы уже знаете, что я имею в виду. Если не просто посмотреть Умножение Матриц


хмм если вы протестируете все версии, которые перечислены здесь, вы увидите, что реализация не является хорошей. вы можете проверить расстояние от центра до каждой сгенерированной точки многоугольника с помощью: http://www.movable-type.co.uk/scripts/latlong.html

теперь я много искал, и я не мог найти хорошей реализации для вычисления полигона с использованием центра и радиуса...поэтому я вернулся к математической книге и попытался реализовать ее сам. В конце концов я придумал это...что на 100% хорошо:

            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

Если вы проверите это, вы увидите, что все точки находятся на точном расстоянии, которое вы даете ( радиус ). Также не забудьте объявить earthRadius.

private const double earthRadius = 6371.01;

это вычисляет координаты десятиугольника. Вы видите, что угол используется 36 градусов. Вы можете разделить 360 градусов на любое количество сторон, которые вы хотите, и поместить результат в переменную угла. В любом случае.. надеюсь, это поможет вам @rmx!


одна из возможных реализаций для создания набора координат для обычного многоугольника:

определение Полигон-центр, радиус и первая вершина1.
Поверните вершину n-раз2 под углом: 360/н.

В этой реализации я использую вектор для хранения сгенерированных координат и рекурсивную функцию для создания они:

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);
}

где:

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);
    }
}

Примечание:

Point-это простой класс для обертывания координаты в единую структуру данных:

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

1 в терминах (относительно) центра, радиуса. В моем случае первая вершина переводится из центра по горизонтали на длину радиуса.

2 n-правильный многоугольник имеет n вершин.


простой метод: Возьмем N-gone (количество сторон) и длину стороны L. угол будет равен T = 360 / N. Допустим, одна вершина расположена на origin.

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

вы можете сделать в for loop