Làm cách nào để tính diện tích của một đa giác 2d?


81

Giả sử một loạt các điểm trong không gian 2d không tự cắt nhau, phương pháp hiệu quả để xác định diện tích của đa giác là gì?

Lưu ý thêm, đây không phải là bài tập về nhà và tôi không tìm kiếm mã. Tôi đang tìm kiếm một mô tả mà tôi có thể sử dụng để triển khai phương pháp của riêng mình. Tôi có ý tưởng của mình về việc kéo một chuỗi tam giác từ danh sách các điểm, nhưng tôi biết có rất nhiều trường hợp cạnh liên quan đến đa giác lồi và lõm mà tôi có thể sẽ không nắm bắt được.


6
Thuật ngữ "diện tích bề mặt" là một chút sai lầm. Những gì bạn có vẻ muốn chỉ là khu vực (thông thường). Trong 3D, diện tích bề mặt là diện tích của bề mặt bên ngoài, do đó, khái quát 2D tự nhiên của khái niệm này sẽ là chiều dài của chu vi của đa giác, rõ ràng không phải là những gì bạn đang tìm kiếm.
batty

khu vực def (đa giác): abs return (numpy.cross (đa giác, numpy.roll (đa giác, -1 Tóm lại, 0)) () / 2.)
iouvxz

Câu trả lời:


110

Đây là phương pháp tiêu chuẩn , AFAIK. Về cơ bản tổng các tích chéo xung quanh mỗi đỉnh. Đơn giản hơn nhiều so với phương pháp tam giác.

Mã Python, cho một đa giác được biểu diễn dưới dạng danh sách tọa độ đỉnh (x, y), bao quanh một cách hoàn toàn từ đỉnh cuối cùng đến đỉnh đầu tiên:

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 nhận xét: Điều đáng nói là tại sao thuật toán này hoạt động: Nó là một ứng dụng của định lý Green cho các hàm −y và x; chính xác theo cách hoạt động của planimeter . Cụ thể hơn:

Công thức trên =
integral_over_perimeter(-y dx + x dy) =
integral_over_area((-(-dy)/dy+dx/dx) dy dx) =
2 Area


7
Điều đáng nói là tại sao thuật toán này hoạt động: Nó là một ứng dụng của định lý Green cho các hàm -y và x; chính xác theo cách hoạt động của planimeter. Cụ thể hơn: Formula trên = integral_permieter (-y dx + x dy) = integral_area ((- (- dy) / dy + dx / dx) dydyx = 2 Diện tích
David Lehavi

6
Liên kết trong bài viết đã chết. Có ai có liên kết khác không?
Yakov

1
Thảo luận được liên kết trên danh sách gửi thư compgeom-discuss@research.bell-labs.com là không thể chấp nhận được đối với tôi. Tôi đã sao chép tin nhắn từ Google Cache: gist.github.com/1200393
Andrew Андрей Листочкин

2
@ perfectm1ng chuyển hướng sẽ lật biển báo trong tổng số, nhưng abs()xóa dấu hiệu.
Darius Bacon

3
Hạn chế: Phương pháp này sẽ tạo ra câu trả lời sai cho các đa giác tự cắt nhau, trong đó một mặt cắt với mặt khác, như hình bên phải. Tuy nhiên, nó sẽ hoạt động chính xác đối với hình tam giác, đa giác đều và không đều, đa giác lồi hoặc lõm. ( mathopenref.com/coordpolygonarea.html )
OneWorld

14

Các sản phẩm chéo là một cổ điển.

Nếu bạn có hàng triệu lần tính toán như vậy, hãy thử phiên bản được tối ưu hóa sau đây yêu cầu ít hơn một nửa số nhân:

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;

Tôi sử dụng chỉ số mảng mảng cho rõ ràng. Sẽ hiệu quả hơn khi sử dụng con trỏ. Mặc dù trình biên dịch tốt sẽ làm điều đó cho bạn.

Đa giác được giả định là "đóng", có nghĩa là bạn sao chép điểm đầu tiên dưới dạng điểm với chỉ số N. Nó cũng giả sử đa giác có số điểm chẵn. Nối thêm một bản sao của điểm đầu tiên nếu N không chẵn.

Thuật toán thu được bằng cách mở và kết hợp hai lần lặp liên tiếp của thuật toán tích chéo cổ điển.

Tôi không chắc chắn hai thuật toán so sánh như thế nào về độ chính xác số. Ấn tượng của tôi là thuật toán trên tốt hơn thuật toán cổ điển vì phép nhân có xu hướng khôi phục lại sự mất độ chính xác của phép trừ. Khi bị hạn chế sử dụng phao nổi, như với GPU, điều này có thể tạo ra sự khác biệt đáng kể.

CHỈNH SỬA: "Diện tích hình tam giác và đa giác 2D & 3D" mô tả một phương pháp thậm chí còn hiệu quả hơn

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

1
Tôi không thể tưởng tượng đoạn mã thứ hai sẽ hoạt động. Rõ ràng là, đa giác càng nằm xa trục X, thì diện tích của nó càng lớn.
Cygon

1
Đó là một sự sắp xếp lại toán học chính xác của thuật toán được mô tả ở trên để tiết kiệm một số phép nhân. Bạn đúng, nhưng diện tích được xác định bởi các đỉnh khác sẽ bị trừ đi. Nhưng điều này thực sự có thể dẫn đến sự suy giảm độ chính xác.
chmike

2
Điều bạn bỏ qua là phép cộng luôn có một số số hạng âm vì phép trừ y. Xét một hình đa giác 2d bất kỳ và so sánh các giá trị y của các đỉnh liên tiếp. Bạn sẽ thấy rằng một số phép trừ sẽ mang lại giá trị âm và một số dương.
chmike

2
Thật vậy, đoạn cuối cùng là điều mà tôi không thể nào quên được! Với i <= N nó hoạt động. Cảm ơn sự kiên nhẫn của bạn, tôi lấy lại mọi thứ :)
Cygon

1
Một lưu ý nhỏ, khu vực được thuật toán trả về là "có dấu" (âm hoặc dương dựa trên thứ tự của điểm) vì vậy nếu bạn muốn khu vực luôn dương chỉ cần sử dụng giá trị tuyệt đối.
NightElfik

11

Trang này cho thấy rằng công thức

nhập mô tả hình ảnh ở đây

có thể được đơn giản hóa thành:

nhập mô tả hình ảnh ở đây

Nếu bạn viết ra một vài thuật ngữ và nhóm chúng theo các yếu tố chung của xi, thì không khó thấy sự bằng nhau.

Tổng cuối cùng hiệu quả hơn vì nó chỉ yêu cầu các nphép nhân thay vì 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

Tôi đã học được cách đơn giản hóa này từ Joe Kington, tại đây .


Nếu bạn có NumPy, phiên bản này nhanh hơn (cho tất cả trừ các mảng rất nhỏ):

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

1
Cảm ơn phiên bản NumPy.
vật lý học Michael


4

Để mở rộng diện tích tam giác và tổng diện tích tam giác, những điều đó sẽ hoạt động nếu bạn tình cờ có một đa giác lồi HOẶC bạn tình cờ chọn một điểm không tạo ra các đường tới mọi điểm khác cắt đa giác.

Đối với một đa giác tổng quát không giao nhau, bạn cần tính tổng tích chéo của các vectơ (điểm tham chiếu, điểm a), (điểm tham chiếu, điểm b) trong đó a và b là "cạnh" nhau.

Giả sử bạn có một danh sách các điểm xác định đa giác theo thứ tự (thứ tự là các điểm i và i + 1 tạo thành một đường thẳng của đa giác):

Tính tổng (tích chéo ((điểm 0, điểm i), (điểm 0, điểm i + 1)) cho i = 1 đến n - 1.

Lấy độ lớn của tích chéo đó và bạn có diện tích bề mặt.

Điều này sẽ xử lý các đa giác lõm mà không phải lo lắng về việc chọn một điểm tham chiếu tốt; bất kỳ ba điểm nào tạo ra một tam giác không nằm bên trong đa giác sẽ có một tích chéo chỉ ngược hướng với bất kỳ tam giác nào nằm bên trong đa giác, do đó các diện tích được tính tổng chính xác.


3

Để tính diện tích của đa giác

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

Đây là một câu hỏi 3 năm tuổi với 34 lượt bình chọn cho câu trả lời được chấp nhận. Hãy cho chúng tôi biết câu trả lời của bạn tốt hơn bất kỳ câu trả lời nào khác đã được đăng.
Mark Taylor

3
Nó là một ví dụ trong c và không phải python. Không tốt hơn nhưng tốt đẹp để có nó trong ngôn ngữ khác nhau
underdoeg

2

Hoặc làm một tích phân đường bao. Định lý Stokes cho phép bạn biểu diễn tích phân diện tích dưới dạng tích phân đường bao. Một góc vuông Gauss nhỏ và Bob là chú của bạn.


2

giải pháp độc lập ngôn ngữ:

GIVEN: một đa giác LUÔN có thể được tạo bởi n-2 tam giác không trùng nhau (n = số điểm HOẶC cạnh). 1 tam giác = đa giác 3 cạnh = 1 tam giác; 1 hình vuông = 4 cạnh đa giác = 2 hình tam giác; vv quảng cáo nauseam QED

do đó, một đa giác có thể được giảm bớt bằng cách "cắt nhỏ" các tam giác và tổng diện tích sẽ là tổng diện tích của các tam giác này. hãy thử nó với một mảnh giấy và kéo, tốt nhất là bạn nên hình dung quy trình trước khi làm theo.

nếu bạn lấy 3 điểm liên tiếp bất kỳ trong một đường đa giác và tạo một hình tam giác với những điểm này, bạn sẽ có một và chỉ một trong ba trường hợp có thể xảy ra:

  1. kết quả tam giác nằm hoàn toàn bên trong đa giác ban đầu
  2. kết quả là tam giác nằm hoàn toàn bên ngoài đa giác ban đầu
  3. tam giác kết quả được chứa một phần trong đa giác ban đầu

chúng tôi chỉ quan tâm đến các trường hợp nằm trong tùy chọn đầu tiên (hoàn toàn chứa).

Mỗi khi chúng tôi tìm thấy một trong số chúng, chúng tôi cắt nó ra, tính diện tích của nó (dễ hiểu, sẽ không giải thích công thức ở đây) và tạo một đa giác mới với một cạnh nhỏ hơn (tương đương với đa giác có tam giác này bị cắt nhỏ). cho đến khi chúng ta chỉ còn lại một tam giác.

cách thực hiện chương trình này:

tạo một mảng (liên tiếp) các điểm biểu diễn đường đi QUA đa giác. bắt đầu từ điểm 0. chạy mảng tạo tam giác (lần lượt) từ các điểm x, x + 1 và x + 2. biến đổi mỗi tam giác từ một hình dạng thành một diện tích và cắt nó với diện tích được tạo ra từ đa giác. NẾU giao điểm kết quả giống với tam giác ban đầu, thì tam giác đó hoàn toàn được chứa trong đa giác và có thể bị cắt nhỏ. xóa x + 1 khỏi mảng và bắt đầu lại từ x = 0. ngược lại (nếu tam giác nằm ngoài [một phần hoặc toàn bộ] đa giác), hãy di chuyển đến điểm tiếp theo x + 1 trong mảng.

Ngoài ra, nếu bạn đang tìm cách tích hợp với lập bản đồ và bắt đầu từ điểm địa lý, bạn phải chuyển đổi từ điểm địa lý sang điểm màn hình ĐẦU TIÊN. điều này đòi hỏi phải quyết định một mô hình và công thức cho hình dạng trái đất (mặc dù chúng ta có xu hướng nghĩ trái đất như một hình cầu, nhưng nó thực sự là một hình trứng không đều (hình trứng), có vết lõm). có rất nhiều mô hình ra khỏi đó, wiki để biết thêm thông tin. một vấn đề quan trọng là bạn sẽ coi khu vực đó là mặt phẳng hay là đường cong. Nói chung, các khu vực "nhỏ", nơi các điểm cách nhau đến vài km, sẽ không tạo ra sai số đáng kể nếu coi là phẳng và không lồi.



1
  1. Đặt một điểm cơ sở (điểm lồi nhất). Đây sẽ là điểm xoay của hình tam giác.
  2. Tính điểm ngoài cùng bên trái (tùy ý), khác với điểm cơ sở của bạn.
  3. Tính điểm thứ 2 bên trái để hoàn thành hình tam giác của bạn.
  4. Tiết kiệm diện tích hình tam giác này.
  5. Di chuyển qua một điểm sang phải mỗi lần lặp lại.
  6. Tính tổng diện tích tam giác

Đảm bảo rằng bạn phủ nhận diện tích tam giác nếu điểm tiếp theo di chuyển "ngược lại".
đệ quy

1

Tốt hơn tính tổng các tam giác là tính tổng các hình thang trong không gian Descartes:

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

Việc thực hiện công thức Dây giày có thể được thực hiện ở Numpy. Giả sử các đỉnh này:

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

Chúng ta có thể định nghĩa hàm sau để tìm vùng:

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

Và nhận được kết quả:

print PolyArea(x,y)
# 0.26353377782163534

Vòng lặp tránh làm cho chức năng này nhanh hơn ~ 50 lần so với 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

Lưu ý: Tôi đã viết câu trả lời này cho một câu hỏi khác , tôi chỉ đề cập điều này ở đây để có một danh sách đầy đủ các giải pháp.


0

Xu hướng của tôi sẽ chỉ đơn giản là bắt đầu cắt các hình tam giác. Tôi không biết làm thế nào khác có thể tránh được việc bị rậm lông khủng khiếp.

Lấy ba điểm liên tiếp tạo thành đa giác. Đảm bảo góc nhỏ hơn 180. Bây giờ bạn có một tam giác mới mà không có vấn đề gì để tính toán, hãy xóa điểm giữa khỏi danh sách các điểm của đa giác. Lặp lại cho đến khi bạn chỉ còn ba điểm.


Điều đáng quan tâm ở đây là nếu ba điểm liên tiếp của bạn xác định một tam giác bên ngoài hoặc một phần bên ngoài của đa giác, thì bạn có vấn đề.
Richard

@Richard: Đó là lý do tại sao trình độ khoảng 180 độ. Nếu bạn cắt một tam giác bên ngoài đa giác, bạn sẽ có quá nhiều độ.
Loren Pechtel

bạn có thể cần phải mô tả rõ hơn cách bạn đang tìm góc. Không có cách nào trong hình học phẳng có 3 điểm là một phần của tam giác và có bất kỳ góc hoặc tổ hợp góc nào vượt quá 180 độ - việc kiểm tra dường như là vô nghĩa.
Richard

@Richard: Trên đa giác của bạn, bạn có góc của mọi đường giao nhau. Nếu tam giác có liên quan nằm bên ngoài đa giác thì góc giữa hai đoạn sẽ lớn hơn 180 độ.
Loren Pechtel

Bạn có nghĩa là góc bên trong của hai đoạn cạnh liền kề sẽ lớn hơn 180 độ.
Richard

0

C cách làm điều đó:

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

Mã Python

Như được mô tả ở đây: http://www.wikihow.com/Calculate-the-Area-of-a-Polygon

Với gấu trúc

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

Tôi sẽ đưa ra một vài hàm đơn giản để tính diện tích của đa giác 2d. Điều này hoạt động cho cả đa giác lồi và lõm. chúng ta chỉ cần chia đa giác thành nhiều tam giác con.

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

cpcó hai đối số, nhưng bạn đang gọi nó bằng một.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.