2D 공간에서 자체 교차하지 않는 일련의 점을 가정 할 때 결과 다각형의 면적을 결정하는 효율적인 방법은 무엇입니까?
참고로 이것은 숙제가 아니며 나는 코드를 찾고 있지 않습니다. 내 자신의 방법을 구현하는 데 사용할 수있는 설명을 찾고 있습니다. 점 목록에서 일련의 삼각형을 가져 오는 것에 대한 아이디어가 있지만 볼록 및 오목 다각형과 관련된 가장자리 사례가 많이 있다는 것을 알고 있습니다.
2D 공간에서 자체 교차하지 않는 일련의 점을 가정 할 때 결과 다각형의 면적을 결정하는 효율적인 방법은 무엇입니까?
참고로 이것은 숙제가 아니며 나는 코드를 찾고 있지 않습니다. 내 자신의 방법을 구현하는 데 사용할 수있는 설명을 찾고 있습니다. 점 목록에서 일련의 삼각형을 가져 오는 것에 대한 아이디어가 있지만 볼록 및 오목 다각형과 관련된 가장자리 사례가 많이 있다는 것을 알고 있습니다.
답변:
다음은 표준 방법 인 AFAIK입니다. 기본적으로 각 정점 주변의 외적을 합산합니다. 삼각 측량보다 훨씬 간단합니다.
(x, y) 꼭지점 좌표의 목록으로 표시된 다각형이 주어진 Python 코드, 마지막 꼭지점에서 첫 번째 꼭짓점으로 암시 적으로 래핑됩니다.
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는 다음과 같이 설명합니다.이 알고리즘이 작동하는 이유를 언급 할 가치가 있습니다. 함수 −y 및 x에 대한 Green의 정리 를 적용한 것입니다 . 면적계가 작동 하는 방식과 정확히 일치 합니다. 더 구체적으로:
위의 공식 =
integral_over_perimeter(-y dx + x dy) =
integral_over_area((-(-dy)/dy+dx/dx) dy dx) =
2 Area
abs()
로그 아웃을 제거합니다.
외적은 고전적입니다.
수행해야 할 이러한 계산이 무궁무진 한 경우 곱셈이 절반으로 줄어드는 다음 최적화 된 버전을 사용해보십시오.
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;
명확성을 위해 배열 첨자를 사용합니다. 포인터를 사용하는 것이 더 효율적입니다. 좋은 컴파일러가 당신을 위해 그것을 할 것이지만.
다각형은 "닫힌"것으로 간주됩니다. 즉, 첫 번째 점을 아래 첨자 N이있는 점으로 복사합니다. 또한 다각형에 짝수의 점이 있다고 가정합니다. N이 짝수가 아니면 첫 번째 점의 추가 사본을 추가하십시오.
이 알고리즘은 고전적인 교차 곱 알고리즘의 두 번의 연속적인 반복을 풀고 결합하여 얻습니다.
두 알고리즘이 수치 정밀도와 관련하여 어떻게 비교되는지 잘 모르겠습니다. 내 인상은 곱셈이 뺄셈의 정밀도 손실을 복원하는 경향이 있기 때문에 위의 알고리즘이 고전적인 알고리즘보다 낫다는 것입니다. GPU와 마찬가지로 부동 소수점을 사용하도록 제한되면 상당한 차이를 만들 수 있습니다.
편집 : "삼각형 및 다각형 영역 2D 및 3D" 는 훨씬 더 효율적인 방법을 설명합니다.
// "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;
이 페이지 는 공식이
다음과 같이 단순화 할 수 있습니다.
몇 가지 용어를 작성하고의 공약수에 따라 그룹화 xi
하면 평등을보기가 어렵지 않습니다.
최종 합산은 n
대신 곱셈 만 필요하므로 더 효율적 입니다 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
저는 여기 에서 Joe Kington으로부터이 단순화를 배웠습니다 .
NumPy가있는 경우이 버전이 더 빠릅니다 (매우 작은 어레이를 제외하고 모두) :
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
다른 제약 조건이없는 점 집합이 반드시 다각형을 고유하게 정의하는 것은 아닙니다.
따라서 먼저이 지점에서 만들 다각형을 결정해야합니다. 볼록 껍질일까요? http://en.wikipedia.org/wiki/Convex_hull
그런 다음 면적을 삼각 측량하고 계산합니다. http://www.mathopenref.com/polygonirregulararea.html
삼각형 영역을 확장하고 삼각형 영역을 합산하려면 볼록 다각형이 있거나 다각형과 교차하는 다른 모든 지점에 선을 생성하지 않는 지점을 선택하면 작동합니다.
일반적인 비교 차 다각형의 경우 a와 b가 서로 "다음"인 벡터 (기준점, 점 a), (기준점, 점 b)의 외적을 합산해야합니다.
순서대로 다각형을 정의하는 점 목록이 있다고 가정합니다 (순서는 점 i 및 i + 1이 다각형의 선을 형성 함).
합계 (외적 ((점 0, 점 i), (점 0, 점 i + 1)) for i = 1 to n-1.
그 외적의 크기를 취하면 표면적이 있습니다.
이것은 좋은 참조 점을 선택하는 것에 대해 걱정할 필요없이 오목한 다각형을 처리합니다. 다각형 내부에 있지 않은 삼각형을 생성하는 세 점은 다각형 내부에있는 삼각형의 반대 방향을 가리키는 외적을 가지므로 영역이 올바르게 합산됩니다.
다각형의 면적을 계산하려면
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);
}
언어 독립적 솔루션 :
GIVEN : 다각형은 항상 겹치지 않는 n-2 개의 삼각형으로 구성 될 수 있습니다 (n = 점 수 또는 변). 1 삼각형 = 3면 다각형 = 1 삼각형; 1 정사각형 = 4면 다각형 = 2 삼각형; 기타 광고 구역질 QED
따라서 삼각형을 "잘라내서"다각형을 줄일 수 있으며 총 면적은 이러한 삼각형의 면적의 합이됩니다. 종이와 가위로 시도해보십시오. 다음 단계를 따르기 전에 프로세스를 시각화하는 것이 가장 좋습니다.
다각형 경로에서 3 개의 연속 된 점을 가져 와서 이러한 점으로 삼각형을 만들면 다음 세 가지 시나리오 중 하나만 사용할 수 있습니다.
첫 번째 옵션 (완전히 포함됨)에 해당하는 경우에만 관심이 있습니다.
우리가 이들 중 하나를 찾을 때마다, 우리는 그것을 잘라 내고, 그것의 면적을 계산하고 (쉽게, 여기에서 공식을 설명하지 않을 것입니다) 한면이 적은 새로운 다각형을 만듭니다 (이 삼각형이 잘린 다각형과 동일). 삼각형이 하나만 남을 때까지.
이것을 프로그래밍 방식으로 구현하는 방법 :
다각형 주위의 경로를 나타내는 (연속적인) 점의 배열을 만듭니다. 점 0에서 시작합니다. 점 x, x + 1 및 x + 2에서 삼각형 (한 번에 하나씩)을 만드는 배열을 실행합니다. 각 삼각형을 모양에서 영역으로 변환하고 다각형에서 만든 영역과 교차합니다. 결과 교차점이 원래 삼각형과 동일하면 해당 삼각형이 다각형에 완전히 포함되어 잘릴 수 있습니다. 배열에서 x + 1을 제거하고 x = 0에서 다시 시작합니다. 그렇지 않으면 (삼각형이 [부분적으로 또는 완전히] 다각형 밖에있는 경우) 배열의 다음 점 x + 1로 이동합니다.
또한 매핑과 통합하려는 경우 지오 포인트에서 시작하는 경우 지오 포인트에서 스크린 포인트로 먼저 변환해야합니다. 이를 위해서는 지구 모양에 대한 모델링과 공식을 결정해야합니다 (우리는 지구를 구로 생각하는 경향이 있지만 실제로는 움푹 들어간 불규칙한 난형 (달걀 모양)입니다). 추가 정보 위키에 대한 많은 모델이 있습니다. 중요한 문제는 해당 영역을 평면인지 곡선인지 여부입니다. 일반적으로 지점이 최대 몇 km 떨어져있는 "작은"영역은 볼록이 아닌 평면을 고려하면 큰 오류를 생성하지 않습니다.
이를 수행하는 한 가지 방법 은 다각형을 삼각형 으로 분해하고 삼각형 의 면적을 계산하고 합계를 다각형의 면적으로 취하는 것입니다.
삼각형을 합하는 것보다 데카르트 공간에서 사다리꼴을 합하는 것이 좋습니다.
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;
}
신발 끈 공식의 구현은 Numpy에서 할 수 있습니다. 다음 정점을 가정합니다.
import numpy as np
x = np.arange(0,1,0.001)
y = np.sqrt(1-x**2)
영역을 찾기 위해 다음 함수를 정의 할 수 있습니다.
def PolyArea(x,y):
return 0.5*np.abs(np.dot(x,np.roll(y,1))-np.dot(y,np.roll(x,1)))
결과 얻기 :
print PolyArea(x,y)
# 0.26353377782163534
루프를 피하면이 함수가 PolygonArea
다음 보다 50 배 더 빠릅니다 .
%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
참고 : 다른 질문에 대해이 답변을 작성했습니다 . 전체 솔루션 목록을 위해 여기에 언급했습니다.
내 경향은 단순히 삼각형을 자르기 시작하는 것입니다. 나는 다른 어떤 것이 끔찍한 털이 피할 수 있는지 보지 못했습니다.
다각형을 구성하는 세 개의 연속적인 점을 취하십시오. 각도가 180 미만인지 확인하십시오. 이제 계산에 문제가없는 새 삼각형이 있습니다. 다각형의 점 목록에서 중간 점을 삭제하십시오. 3 점만 남을 때까지 반복하십시오.
여기에 설명 된대로 : http://www.wikihow.com/Calculate-the-Area-of-a-Polygon
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
2D 폴리곤의 면적을 계산하기위한 몇 가지 간단한 함수를 제공하겠습니다. 이것은 볼록한 다각형과 오목한 다각형 모두에 적용됩니다. 우리는 단순히 다각형을 많은 하위 삼각형으로 나눕니다.
//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;
}