it-swarm.com.de

Wie berechne ich die Fläche eines 2d-Polygons?

Angenommen, eine Reihe von Punkten im 2d-Raum, die sich nicht selbst schneiden, was ist eine effiziente Methode zur Bestimmung der Fläche des resultierenden Polygons?

Als Randbemerkung sind dies keine Hausaufgaben und ich suche keinen Code. Ich suche nach einer Beschreibung, mit der ich meine eigene Methode implementieren kann. Ich habe meine Ideen, eine Reihe von Dreiecken aus der Liste der Punkte zu ziehen, aber ich weiß, dass es eine Reihe von Edge-Fällen bezüglich konvexer und konkaver Polygone gibt, die ich wahrscheinlich nicht fangen kann.

72
Jason Z

Hier ist die Standardmethode , AFAIK. Summieren Sie im Grunde die Querprodukte um jeden Scheitelpunkt. Viel einfacher als Triangulation.

Python-Code unter Angabe eines Polygons, das als Liste von (x, y) Eckpunktkoordinaten dargestellt wird und implizit vom letzten zum ersten Eckpunkt umgebrochen wird:

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 kommentiert: Es ist erwähnenswert, warum dieser Algorithmus funktioniert: Es ist eine Anwendung von Green's Theorem für die Funktionen −y und x; Genau so funktioniert ein Planimeter . Genauer:

Formel oben =
integral_over_perimeter(-y dx + x dy) =
integral_over_area((-(-dy)/dy+dx/dx) dy dx) =
2 Area

100
Darius Bacon

Das Kreuzprodukt ist ein Klassiker. 

Wenn Sie unzählige solcher Berechnungen durchführen müssen, versuchen Sie die folgende optimierte Version, die die Hälfte der Multiplikationen erfordert:

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;

Ich verwende zur Vereinfachung ein Array-Index. Es ist effizienter, Zeiger zu verwenden. Obwohl gute Compiler es für Sie tun werden. 

Es wird angenommen, dass das Polygon "geschlossen" ist, was bedeutet, dass Sie den ersten Punkt als Punkt mit dem Index N kopieren. Es wird auch davon ausgegangen, dass das Polygon eine gerade Anzahl von Punkten hat. Fügen Sie eine zusätzliche Kopie des ersten Punkts an, wenn N nicht gerade ist. 

Der Algorithmus wird durch Abrollen und Kombinieren zweier aufeinanderfolgender Iterationen des klassischen Kreuzproduktalgorithmus erhalten. 

Ich bin mir nicht so sicher, wie sich die beiden Algorithmen hinsichtlich der numerischen Genauigkeit vergleichen. Mein Eindruck ist, dass der obige Algorithmus besser ist als der klassische, da die Multiplikation dazu neigt, den Genauigkeitsverlust der Subtraktion wieder herzustellen. Wenn die Verwendung von Floats wie bei der GPU eingeschränkt ist, kann dies einen erheblichen Unterschied bewirken. 

BEARBEITEN: "Bereich der Dreiecke und Polygone 2D & 3D" beschreibt eine noch effizientere Methode

// "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

Diese Seite zeigt die Formel

enter image description here

kann vereinfacht werden zu:

enter image description here

Wenn Sie einige Begriffe ausschreiben und sie nach den üblichen Faktoren von xi gruppieren, ist die Gleichheit nicht schwer zu erkennen.

Die endgültige Summation ist effizienter, da statt 2n nur n Multiplikationen erforderlich sind.

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

Ich habe diese Vereinfachung von Joe Kington gelernt, hier .


Wenn Sie NumPy haben, ist diese Version schneller (für alle außer sehr kleinen Arrays):

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

Eine Menge von Punkten ohne andere Einschränkungen definiert ein Polygon nicht unbedingt eindeutig.

Also müssen Sie zuerst entscheiden, welches Polygon aus diesen Punkten erstellt werden soll - vielleicht die konvexe Hülle? http://en.wikipedia.org/wiki/Convex_hull

Triangulieren und berechnen Sie dann die Fläche. http://www.mathopenref.com/polygonirregulararea.html

4
mbeckish

Um die Dreiecks- und Dreieckbereiche zu erweitern, funktionieren diese, wenn Sie ein konvexes Polygon OR haben, und wählen einen Punkt aus, der keine Linien zu jedem anderen Punkt erzeugt, der das Polygon schneidet.

Für ein allgemeines, sich nicht überschneidendes Polygon müssen Sie das Kreuzprodukt der Vektoren (Bezugspunkt, Punkt a), (Bezugspunkt, Punkt b) summieren, wobei a und b "nächste" sind.

Angenommen, Sie verfügen über eine Liste von Punkten, die das Polygon in der Reihenfolge definieren (die Reihenfolge sind die Punkte i und i + 1 bilden eine Linie des Polygons):

Summe (Kreuzprodukt ((Punkt 0, Punkt i), (Punkt 0, Punkt i + 1)) für i = 1 bis n - 1.

Nehmen Sie die Größe dieses Kreuzprodukts und Sie haben die Oberfläche.

Dadurch werden konkave Polygone behandelt, ohne sich um die Auswahl eines guten Bezugspunkts sorgen zu müssen. Alle drei Punkte, die ein Dreieck erzeugen, das nicht innerhalb des Polygons liegt, haben ein Kreuzprodukt, das in die entgegengesetzte Richtung eines Dreiecks innerhalb des Polygons zeigt, sodass die Bereiche korrekt summiert werden.

4
MSN

So berechnen Sie die Fläche des Polygons

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

Oder machen Sie ein Konturintegral. Mit dem Satz von Stokes können Sie ein Flächenintegral als Konturintegral ausdrücken. Ein bisschen Gauß-Quadratur und Bob ist dein Onkel.

2
duffymo

Besser als das Summieren von Dreiecken ist das Summieren von Trapezen im kartesischen Raum:

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

Eine Möglichkeit wäre, das Polygon in Dreiecke zerlegen , die Fläche der Dreiecke zu berechnen und die Summe als Fläche des Polygons zu nehmen.

1
MattK
  1. Legen Sie einen Basispunkt (den konvexsten Punkt) fest. Dies ist der Drehpunkt der Dreiecke.
  2. Berechnen Sie den am weitesten links liegenden Punkt (willkürlich), abgesehen von Ihrem Basispunkt.
  3. Berechnen Sie den am weitesten links liegenden Punkt, um Ihr Dreieck zu vervollständigen.
  4. Speichern Sie diesen triangulierten Bereich.
  5. Bewegen Sie sich bei jeder Iteration um einen Punkt nach rechts.
  6. Summe der triangulierten Bereiche
1
Joe Phillips

Implementierung der Shoelace-Formel könnte in Numpy durchgeführt werden. Angenommen diese Scheitelpunkte:

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

Wir können die folgende Funktion definieren, um den Bereich zu finden:

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

Und Ergebnisse erzielen:

print PolyArea(x,y)
# 0.26353377782163534

Das Vermeiden einer Schleife macht diese Funktion ~ 50X schneller als 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

Hinweis: Ich hatte diese Antwort für eine andere Frage geschrieben. Ich erwähne dies hier nur, um eine vollständige Liste von Lösungen zu erhalten.

1
Mahdi

sprachunabhängige Lösung: 

GIVEN: Ein Polygon kann IMMER aus n-2 Dreiecken bestehen, die sich nicht überlappen (n = Anzahl der Punkte OR). 1 Dreieck = 3-seitiges Polygon = 1 Dreieck; 1 Quadrat = 4-seitiges Polygon = 2 Dreiecke; usw ad nauseam QED

daher kann ein Polygon durch "Abschneiden" von Dreiecken reduziert werden, und die Gesamtfläche ergibt sich aus der Summe der Flächen dieser Dreiecke. Probieren Sie es mit einem Stück Papier und einer Schere aus. Am besten können Sie den Prozess vor dem weiteren Vorgehen visualisieren.

wenn Sie drei aufeinanderfolgende Punkte in einem Polygonpfad nehmen und ein Dreieck mit diesen Punkten erstellen, haben Sie nur eines von drei möglichen Szenarien:

  1. das resultierende Dreieck befindet sich vollständig innerhalb des ursprünglichen Polygons
  2. das resultierende Dreieck befindet sich vollständig außerhalb des ursprünglichen Polygons
  3. das resultierende Dreieck ist teilweise im ursprünglichen Polygon enthalten

wir sind nur an Fällen interessiert, die in die erste Option fallen (vollständig enthalten). 

jedes Mal, wenn wir eines davon finden, schneiden wir es ab, berechnen seine Fläche (einfach peasy, erklären hier nicht die Formel) und erstellen ein neues Polygon mit einer Seite weniger (entspricht einem Polygon mit abgeschnittenem Dreieck). bis wir nur noch ein Dreieck haben.

wie man dies programmatisch umsetzt:

erstellen Sie ein Array von (aufeinander folgenden) Punkten, die den Pfad um das Polygon darstellen. Beginnen Sie mit Punkt 0. Starten Sie das Array und machen Sie aus den Punkten x, x + 1 und x + 2 Dreiecke (einzeln). wandeln Sie jedes Dreieck von einer Form in eine Fläche um und schneiden Sie es mit einer aus Polygon erstellten Fläche. Wenn der resultierende Schnittpunkt mit dem ursprünglichen Dreieck identisch ist, ist das Dreieck vollständig im Polygon enthalten und kann abgeschnitten werden. Entfernen Sie x + 1 aus dem Array und beginnen Sie erneut von x = 0. Andernfalls (wenn das Dreieck außerhalb des Polygons liegt), fahren Sie mit dem nächsten Punkt x + 1 im Array fort.

wenn Sie darüber hinaus in das Mapping integrieren möchten und von Geopunkten aus starten, müssen Sie zunächst von Geopunkten auf Screenpunkte FIRST konvertieren. Dies erfordert die Festlegung einer Modellierung und einer Formel für die Form der Erde (obwohl wir die Erde eher als Kugel betrachten, ist sie tatsächlich ein unregelmäßiges Ovoid (Eiform) mit Beulen). Es gibt viele Modelle für weitere Info-Wiki. Eine wichtige Frage ist, ob Sie die Fläche als eben oder gekrümmt betrachten. Im Allgemeinen erzeugen "kleine" Gebiete, in denen die Punkte einige Kilometer voneinander entfernt sind, keinen signifikanten Fehler, wenn sie planar und nicht konvex betrachtet werden.

1
user836725

Meine Neigung wäre, einfach Dreiecke abzuschneiden. Ich sehe nicht, wie etwas anderes verhindern kann, dass man schrecklich behaart ist.

Nehmen Sie drei aufeinanderfolgende Punkte, die das Polygon umfassen. Stellen Sie sicher, dass der Winkel weniger als 180 beträgt. Sie haben jetzt ein neues Dreieck, das sich problemlos berechnen lässt. Löschen Sie den Mittelpunkt aus der Liste der Punkte des Polygons. Wiederholen Sie dies, bis Sie nur noch drei Punkte haben.

0
Loren Pechtel

Ich werde ein paar einfache Funktionen zum Berechnen der Fläche des 2d-Polygons geben. Dies funktioniert sowohl für konvexe als auch für konkave Polygone. Wir teilen das Polygon einfach in viele Unterdreiecke auf.

//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

Wie das geht:

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

Python-Code

Wie hier beschrieben: http://www.wikihow.com/Calculate-the-Area-of-a-Polygon

Mit 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