web-dev-qa-db-fra.com

Calculer les coordonnées des sommets d'un polygone régulier

J'écris un programme dans lequel je dois dessiner des polygones d'un nombre arbitraire de côtés, chacun d'eux étant traduit par une formule donnée qui change de manière dynamique. Il y a quelques mathématiques assez intéressantes impliquées mais je suis coincé sur ce problème.

Comment puis-je calculer les coordonnées des sommets d'un polygone régulier (celui dans lequel tous les angles sont égaux), étant donné uniquement le nombre de côtés et idéalement (mais pas nécessairement) ayant l'origine au centre?

Par exemple: un hexagone peut avoir les points suivants (tous sont 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) )

Ma méthode ressemble à ceci: 

void InitPolygonVertexCoords(RegularPolygon poly)

et les coordonnées doivent être ajoutées à ceci (ou quelque chose de similaire, comme une liste):

Point[] _polygonVertexPoints;

L'algorithme m'intéresse principalement ici, mais des exemples en C # seraient utiles. Je ne sais même pas par où commencer. Comment dois-je le mettre en œuvre? Est-ce même possible?!

Je vous remercie.

25
Nobody
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 est le rayon du cercle de circonscription. Désolé pour la mauvaise langue Non Habla C #.

Fondamentalement, l'angle entre deux sommets quelconques est 2 pi/n et tous les sommets sont situés à la distance r de l'origine.

EDIT: Si vous voulez avoir le centre autre que l’Origine, dites à (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));
}
52
deinst

Le nombre de points est égal au nombre de côtés.

L'angle dont vous avez besoin est angle = 2 * pi / numPoints.

Puis en commençant verticalement au-dessus de l’origine, la taille du polygone étant donnée par radius:

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

Si votre centre est l’origine, ignorez simplement les termes centreX et centreY car ils seront 0,0.

Si vous permutez cos et sin, le premier point sera horizontalement à droite de l'origine.

20
ChrisF

Désolé, je n'ai pas de solution complète à portée de main pour le moment, mais vous devriez essayer de rechercher le rendu 2D de cercles. Toutes les implémentations classiques de circle (x, y, r) utilisent un polygone comme décrit pour le dessin (mais avec plus de 50 côtés).

2
Rock

Disons que la distance des sommets à l'origine est 1. Et disons (1, 0) est toujours une coordonnée du polygone.

Étant donné le nombre de sommets (disons n), l'angle de rotation requis pour positionner le (1, 0) sur la coordonnée suivante serait (360/n).

Le calcul requis ici consiste à faire pivoter les coordonnées. Voici ce que c'est; Matrice de rotation .

Disons thêta = 360/n;

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

serait votre matrice de rotation.

Si vous connaissez l'algèbre linéaire, vous savez déjà ce que je veux dire. Si vous n'avez pas à regarder Matrix Multiplication } _

2
tafa

hmm si vous testez toutes les versions répertoriées ici, vous verrez que la mise en œuvre n'est pas bonne. vous pouvez vérifier la distance entre le centre et chaque point généré du polygone avec: http://www.movable-type.co.uk/scripts/latlong.html

Maintenant, j'ai beaucoup cherché et je ne pouvais trouver aucune bonne implémentation pour calculer un polyogon en utilisant le centre et le rayon ... alors je suis retourné au livre de mathématiques et j'ai essayé de le mettre en œuvre moi-même. En fin de compte, j'ai trouvé ceci ... qui est 100% bon:

            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

Si vous testez cela, vous verrez que tous les points sont à la distance exacte que vous donnez (rayon). De plus, n'oubliez pas de déclarer le earthRadius. 

private const double earthRadius = 6371.01;

Ceci calcule les coordonnées d'un décagone. Vous voyez l'angle utilisé est de 36 degrés. Vous pouvez diviser 360 degrés en un nombre quelconque de côtés et placer le résultat dans la variable angle. Quoi qu'il en soit .. j'espère que cela vous aidera @rmx!

0
danvasiloiu

Une implémentation possible pour générer un ensemble de coordonnées pour un polygone régulier consiste à:

Définir centre du polygone , rayon et premier sommet 1.
Faire pivoter le sommet n fois2 sous un angle de: 360/n. 

Dans cette implémentation, j'utilise un vecteur pour stocker les coordonnées générées et une fonction récursive pour les générer:

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

où:

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

Remarque:

Point est une classe simple permettant de regrouper les coordonnées dans une structure de données unique:

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

1 en termes de (par rapport à) le centre, le rayon. Dans mon cas, le premier sommet est déplacé horizontalement du centre vers le haut par la longueur du rayon.

2 polygones réguliers ont n sommets.

0
Ziezi