web-dev-qa-db-fra.com

Comment calculer l'aire d'un polygone 2d?

En supposant une série de points dans l'espace 2d qui ne s'entrecroisent pas, quelle est une méthode efficace pour déterminer l'aire du polygone résultant?

En remarque, ce n’est pas un devoir et je ne cherche pas de code. Je cherche une description que je peux utiliser pour mettre en œuvre ma propre méthode. J'ai des idées sur le fait de tirer une séquence de triangles de la liste de points, mais je sais qu'il y a beaucoup de cas Edge qui concernent des polygones convexes et concaves que je ne comprendrai probablement pas.

72
Jason Z

Voici la méthode standard , autant que je sache. En somme, résumez les produits croisés autour de chaque sommet. Beaucoup plus simple que la triangulation.

Le code Python, à partir d’un polygone représenté par une liste de coordonnées de sommets (x, y), enveloppe de manière implicite le dernier sommet au premier:

def area(p):
    return 0.5 * abs(sum(x0*y1 - x1*y0
                         for ((x0, y0), (x1, y1)) in segments(p)))

def segments(p):
    return Zip(p, p[1:] + [p[0]])

David Lehavi a commenté: Pourquoi cet algorithme fonctionne-t-il? C’est une application de théorème de Green pour les fonctions -y et x; exactement de la manière dont un planimètre fonctionne. Plus précisement:

Formule ci-dessus =
integral_over_perimeter(-y dx + x dy) =
integral_over_area((-(-dy)/dy+dx/dx) dy dx) =
2 Area

100
Darius Bacon

Le produit croisé est un classique. 

Si vous avez des millions de calculs à effectuer, essayez la version optimisée suivante qui nécessite une multiplication par moitié inférieure:

area = 0;
for( i = 0; i < N; i += 2 )
   area += x[i+1]*(y[i+2]-y[i]) + y[i+1]*(x[i]-x[i+2]);
area /= 2;

J'utilise l'indice de tableau pour plus de clarté. Il est plus efficace d’utiliser des pointeurs. Bien que les bons compilateurs le fassent pour vous. 

Le polygone est supposé être "fermé", ce qui signifie que vous copiez le premier point en tant que point avec l'indice N. Il suppose également que le polygone a un nombre pair de points. Ajoutez une copie supplémentaire du premier point si N n'est pas pair. 

L'algorithme est obtenu en déroulant et en combinant deux itérations successives de l'algorithme classique multi-produits. 

Je ne suis pas sûr de savoir comment les deux algorithmes se comparent en ce qui concerne la précision numérique. Mon impression est que l'algorithme ci-dessus est meilleur que l'algorithme classique car la multiplication tend à restaurer la perte de précision de la soustraction. Lorsque contraint d'utiliser des flotteurs, comme avec le GPU, cela peut faire une différence significative. 

EDIT: "Zone de triangles et polygones 2D & 3D" décrit une méthode encore plus efficace

// "close" polygon
x[N] = x[0];
x[N+1] = x[1];
y[N] = y[0];
y[N+1] = y[1];

// compute area
area = 0;
for( size_t i = 1; i <= N; ++i )
  area += x[i]*( y[i+1] - y[i-1] );
area /= 2;
14
chmike

Cette page montre que la formule

enter image description here

peut être simplifié à:

enter image description here

Si vous écrivez quelques termes et que vous les regroupez en fonction de facteurs communs de xi, l'égalité n'est pas difficile à voir.

La sommation finale est plus efficace car elle nécessite seulement des multiplications n au lieu de 2n.

def area(x, y):
    return abs(sum(x[i] * (y[i + 1] - y[i - 1]) for i in xrange(-1, len(x) - 1))) / 2.0

J'ai appris cette simplification de Joe Kington, ici .


Si vous avez NumPy, cette version est plus rapide (pour tous les tableaux sauf les très petits):

def area_np(x, y):        
    x = np.asanyarray(x)
    y = np.asanyarray(y)
    n = len(x)
    shift_up = np.arange(-n+1, 1)
    shift_down = np.arange(-1, n-1)    
    return (x * (y.take(shift_up) - y.take(shift_down))).sum() / 2.0
8
unutbu

Un ensemble de points sans autre contrainte ne définit pas nécessairement un polygone de manière unique.

Donc, vous devez d’abord décider quel polygone construire à partir de ces points - peut-être la coque convexe? http://en.wikipedia.org/wiki/Convex_hull

Puis trianguler et calculer la surface. http://www.mathopenref.com/polygonirregulararea.html

4
mbeckish

Pour développer les triangles et les sommets, ceux-ci fonctionnent si vous avez un polygone convexe OR, vous choisissez un point qui ne génère pas de lignes à chaque point qui intersecte le polygone.

Pour un polygone général ne se croisant pas, vous devez additionner le produit croisé des vecteurs (point de référence, point a), (point de référence, point b) où a et b sont "proches" l'un de l'autre.

En supposant que vous ayez une liste de points définissant le polygone dans l'ordre (les points i et i + 1 formant une ligne forment une ligne du polygone):

Somme (produit croisé ((point 0, point i), (point 0, point i + 1)) pour i = 1 à n - 1.

Prenez la magnitude de ce produit croisé et vous avez la surface.

Cela permettra de gérer des polygones concaves sans avoir à se soucier de choisir un bon point de référence. Les trois points qui génèrent un triangle qui ne se trouve pas à l'intérieur du polygone auront un produit croisé qui pointe dans la direction opposée de tout triangle se trouvant à l'intérieur du polygone, de sorte que les zones sont additionnées correctement.

4
MSN

Calculer l'aire du polygone

http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=geometry1#polygon_area

int cross(vct a,vct b,vct c)
{
    vct ab,bc;
    ab=b-a;
    bc=c-b;
    return ab.x*bc.y-ab.y*bc.x;
}    
double area(vct p[],int n)
{ 
    int ar=0;
    for(i=1;i+1<n;i++)
    {
        vct a=p[i]-p[0];
        vct b=p[i+1]-p[0];
        area+=cross(a,b);
    }
    return abs(area/2.0);
}    
3
Steve

Ou faire une intégrale de contour. Le théorème de Stokes vous permet d'exprimer une intégrale de surface sous la forme d'une intégrale de contour. Un peu en quadrature de Gauss et Bob est ton oncle.

2
duffymo

Mieux que de sommer des triangles, sommer des trapèzes dans l’espace cartésien

area = 0;
for (i = 0; i < n; i++) {
  i1 = (i + 1) % n;
  area += (vertex[i].y + vertex[i1].y) * (vertex[i1].x - vertex[i].x) / 2.0;
}
1
David Hanak

Une façon de le faire serait de décomposer le polygone en triangles , calculer l'aire des triangles et prendre la somme comme étant l'aire du polygone.

1
MattK
  1. Définissez un point de base (le point le plus convexe). Ce sera votre pivot des triangles.
  2. Calculez le point le plus à gauche (arbitraire), autre que votre point de base.
  3. Calculez le deuxième point le plus à gauche pour compléter votre triangle.
  4. Enregistrez cette zone triangulée.
  5. Déplacez le curseur d'un point vers la droite à chaque itération.
  6. Somme les zones triangulées
1
Joe Phillips

La mise en œuvre de Formule de lacet pourrait être effectuée dans Numpy. En supposant que ces sommets:

import numpy as np
x = np.arange(0,1,0.001)
y = np.sqrt(1-x**2)

Nous pouvons définir la fonction suivante pour trouver une zone:

def PolyArea(x,y):
    return 0.5*np.abs(np.dot(x,np.roll(y,1))-np.dot(y,np.roll(x,1)))

Et obtenir des résultats:

print PolyArea(x,y)
# 0.26353377782163534

En évitant les boucles, cette fonction est environ 50 fois plus rapide que PolygonArea:

%timeit PolyArea(x,y)
# 10000 loops, best of 3: 42 µs per loop
%timeit PolygonArea(Zip(x,y))
# 100 loops, best of 3: 2.09 ms per loop

Remarque: j'avais écrit cette réponse pour une autre question , je le mentionne juste ici pour avoir une liste complète des solutions.

1
Mahdi

solution indépendante de la langue: 

DONNÉ: un polygone peut TOUJOURS être composé de n-2 triangles qui ne se chevauchent pas (n = nombre de points OR côtés). 1 triangle = polygone à 3 côtés = 1 triangle; 1 carré = polygone à 4 côtés = 2 triangles; etc ad nauseam QED

par conséquent, un polygone peut être réduit en "découpant" des triangles et la surface totale sera la somme des surfaces de ces triangles. essayez-le avec un morceau de papier et des ciseaux, il est préférable de pouvoir visualiser le processus avant de le suivre.

si vous prenez 3 points consécutifs dans un tracé de polygones et créez un triangle avec ces points, vous aurez un et un seul des trois scénarios possibles:

  1. le triangle résultant est complètement à l'intérieur du polygone d'origine
  2. le triangle résultant est totalement en dehors du polygone d'origine
  3. le triangle résultant est partiellement contenu dans le polygone d'origine

nous nous intéressons uniquement aux cas qui relèvent de la première option (totalement contenus). 

chaque fois que nous trouvons un de ceux-ci, nous le découpons, calculons sa surface (facile, nous n'expliquons pas la formule ici) et créons un nouveau polygone avec un côté de moins (équivalent au polygone avec ce triangle coupé). jusqu'à ce qu'il ne reste qu'un triangle.

comment implémenter cette programmation:

créer un tableau de points (consécutifs) représentant le chemin AUTOUR du polygone. commencez au point 0. exécutez le tableau en créant des triangles (un à la fois) à partir des points x, x + 1 et x + 2. transformer chaque triangle d'une forme en une zone et l'intersecter avec une zone créée à partir d'un polygone. Si l'intersection résultante est identique au triangle d'origine, il est alors totalement contenu dans le polygone et peut être découpé. retirez x + 1 du tableau et recommencez à partir de x = 0. sinon (si le triangle est en dehors du polygone [partiellement ou complètement]), passez au point suivant x + 1 dans le tableau.

en outre, si vous souhaitez intégrer la cartographie et que vous démarrez à partir de géopoints, vous devez d'abord convertir les géopoints en points d'écran. cela nécessite de choisir un modèle et une formule pour la forme de la terre (bien que nous ayons tendance à penser que la terre est une sphère, il s’agit en fait d’un ovoïde irrégulier (egghape), avec des bosses). Il existe de nombreux modèles, pour plus d'informations sur le wiki. Une question importante est de savoir si vous considérerez ou non que la zone est plane ou courbe. en général, les "petites" zones, où les points sont éloignés de quelques km, ne généreront pas d'erreur significative si elles sont planes et non convexes.

1
user836725

Mon inclination serait de commencer simplement à couper des triangles. Je ne vois pas comment autre chose pourrait éviter d'être terriblement velu.

Prendre trois points séquentiels qui composent le polygone. Assurez-vous que l'angle est inférieur à 180. Vous avez maintenant un nouveau triangle dont le calcul ne devrait pas poser de problème: supprimez le point central de la liste de points du polygone. Répétez jusqu'à ce qu'il ne vous reste que trois points.

0
Loren Pechtel

Je vais vous donner quelques fonctions simples pour calculer l’aire du polygone 2d. Cela fonctionne à la fois pour les polygones convexes et concaves. nous divisons simplement le polygone en plusieurs sous-triangles.

//don't forget to include cmath for abs function
struct Point{
  double x;
  double y;
}
// cross_product
double cp(Point a, Point b){ //returns cross product
  return a.x*b.y-a.y*b.x;
}

double area(Point * vertices, int n){  //n is number of sides
  double sum=0.0;
  for(i=0; i<n; i++){
    sum+=cp(vertices[i], vertices[(i+1)%n]); //%n is for last triangle
  }
  return abs(sum)/2.0;
}
0
abe312

C façon de faire ça:

float areaForPoly(const int numVerts, const Point *verts)
{
    Point v2;
    float area = 0.0f;

    for (int i = 0; i<numVerts; i++){
        v2 = verts[(i + 1) % numVerts];
        area += verts[i].x*v2.y - verts[i].y*v2.x;
    }

    return area / 2.0f;
}
0
Joseph

Code python

Comme décrit ici: http://www.wikihow.com/Calcul-the-Area-of-a-Polygon

Avec des pandas

import pandas as pd

df = pd.DataFrame({'x': [10, 20, 20, 30, 20, 10, 0], 'y': [-10, -10, -10, 0, 10, 30, 20]})
df = df.append(df.loc[0])

first_product = (df['x'].shift(1) * df['y']).fillna(0).sum()
second_product = (df['y'].shift(1) * df['x']).fillna(0).sum()

(first_product - second_product) / 2
600
0
firelynx