Вычислить координаты вершин правильного многоугольника - PullRequest
27 голосов
/ 09 августа 2010

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

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

Например: шестиугольник может иметь следующие точки (все они float s):

( 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;

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

Спасибо.

Ответы [ 7 ]

54 голосов
/ 09 августа 2010
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));
}
20 голосов
/ 09 августа 2010

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

Нужный вам угол равен 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.

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

2 голосов
/ 09 августа 2010

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

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

Требуемое здесь вычисление заключается в повороте координат.Вот что это такое; Матрица вращения .

Скажите, что тета = 360 / n;

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

будет вашей матрицей вращения.

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

2 голосов
/ 09 августа 2010

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

0 голосов
/ 23 сентября 2015

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

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

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

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

Примечание:

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

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 вершин.

0 голосов
/ 26 января 2015

хмм, если вы протестируете все версии, перечисленные здесь, вы увидите, что реализация не очень хорошая. Вы можете проверить расстояние от центра до каждой созданной точки многоугольника с помощью: 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!

0 голосов
/ 20 ноября 2010

Простой метод: возьмем N-ушел (количество сторон) и длину стороны L. Угол будет Т = 360 / N.Допустим, одна вершина находится в начале координат.

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

Вы можете сделать цикл for

...