불규칙한 모양의 면적을 계산하는 방법?


17

면적을 계산 해야하는 루핑 선 세그먼트 모음으로 정의 된 룸 객체가 있습니다. 클래스는 다음과 같이 설명 할 수 있습니다 (의사 코드로).

class Point {
    float x; 
    float y;
    ...
    float distanceFrom(Point p);
}

class Segment {
    Point start;
    Point end;
    ...
    float length();
}

class Room {
    List<Segment> walls;
    ...
    float area();
}

방의 벽은 어디에서나 교차 할 수 없지만 세그먼트의 끝점과 생성 된 "하위 루프"도 새 방으로 분리됩니다. 이 솔루션은 완벽하게 정확할 필요는 없으며 (10 %의 오차 한계가 허용됨) 매우 자주 계산되지도 않습니다 (<1 / s).


7
Room의 목록을 포함하고 Point각 지점을 연결하여 세그먼트를 가져 와서 다시 반복하는 것이 더 합리적입니다 . 그렇지 않으면 현재 설정에서 잘못된 값 (예 : 닫히지 않은 방, 중간에 벽이있는 방 등)을 얻는 것이 매우 동쪽입니다. 이것이 최선의 선택입니다.
MCMastery

다른 옵션은 모양을 위쪽으로 삼각 측량하고 각 삼각형의 면적을 계산하는 것입니다. 어려운 부분은 삼각 측량입니다. 가능하지만 항상 예쁘지는 않습니다. 신발 끈 답은 여전히 ​​낫습니다.
Draco18s는 더 이상 SE

@MCMastery이 솔루션은 Rooms가 항상 완전 해야 하기 때문에 작동 하지 않으며, 플레이어가 Rooms를 사용하여 Segments를 빌드하면 그렇지 않을 수 있습니다 . 또한 폐쇄 룸 기능은 쉽게 정의 할 수 있습니다 ( Segments를 반복 하고 룸을 생성하는지 확인).

답변:


31

Gauss의 신발 끈 공식을 사용할 수 있습니다 .

모든 점의 x 좌표를 가져 와서 다음 점의 y 좌표를 곱한 다음 결과에서 다음 점의 x 좌표를 곱한 현재 점의 y 좌표를 빼고 전체 영역에 추가해야합니다. 모든 점에 대해이 작업을 수행 한 후 총 면적을 절반으로 줄여 다각형의 실제 면적을 얻습니다. 현재 점이 마지막 점이면 다음 점이 첫 번째 점입니다.

A = 0

for (i = 0; i < points.length; i++) do

    A += points[i].x * points[(i + 1) % points.length].y - points[i].y * points[(i + 1) % points.length].x

end

A /= 2

2
저는 항상 두 벡터의 교차 곱을 계산하기 위해 신발 끈 알고리즘이라고하는 것을 전혀 몰랐습니다.
Sidar

3
이것은 삼각형으로 만들어진 불규칙한 3D 물체의 부피를 계산하기 위해 확장 될 수 있으며 미적분학의 기본 정리의 사소한 경우로 간주 될 수 있습니다.
Dietrich Epp

5
여기에 서명 된 영역입니다. 다른 방향으로 포인트를 통과하고 최종 A은 부정됩니다. 목표에 따라 A = |A|가 필요할 수 있습니다. 음수 지역 코드를 사용하면 내부 및 외부 지점 목록을 사용하여 불규칙한 도넛에서 해당 지역을 찾을 수 있습니다 (하나는 반대 순서로).
chux-복원 모니카

6
물론 Gauss 또는 Euler는 이에 대한 공식을 가지고 있습니다.
corsiKa

0

Monte Carlo 방법을 사용할 수도 있습니다.

임의의 모양 주위에 사각형을 그립니다. 균일하게 분포 된 PRNG 소스를 사용하십시오. 그런 다음 모듈러스 함수를 사용하여 사각형의 X, Y 길이로 출력을 바인딩합니다. 아니오를 세십시오. 모양 안에있는 임의의 점들. 생성 된 총 포인트 수로 나눕니다. 그 몫에 사각형의 면적을 곱하십시오. 각 반복마다 실제 영역으로 수렴됩니다. 이 알고리즘은 엄청나게 병렬화 할 수 있으며 R ^ N 좌표가 모양의 R ^ N 경계 내에 있는지 여부를 결정할 수있는 한 임의의 차원 모양 '볼륨'을 계산하는 데 사용할 수 있습니다.

.

여기 누군가 가이 방법으로 서클 영역 찾기를 사용하여 파이를 계산하는 데 사용합니다 https://www.youtube.com/watch?v=VJTFfIqO4TU


2
-1 : 범위를 얻기 위해 모듈로를 사용하고 싶지 않고 균일 한 분포 또는 다른 분포를 사용하고 싶습니다. 모듈로 방식에는 모든 종류의 통계 문제가 있습니다.
user1997744

12
이 방법은 단순한 다각형이 아닌 프랙탈이나 메타 볼 얼룩과 같이 테두리를 표현하기 어려운 암시 적 모양 일 때 유용합니다. 그러나 질문에서와 같은 다각형의 경우, 그것은 비용이 많이 드는 것처럼 보입니다.
DMGregory

@DMGregory가 지적했듯이 이것은 내가 찾고있는 것이 아닙니다. 그러나 다른 사람이 필요할 경우 +1이 필요하다고 생각합니다.

이것은 흥미롭지 만 포함 테스트 비용이 엄청 나지 않습니까? 즉,이 접근 방식을 보장하기에 충분히 복잡한 형태를 가지고 있다면 포함 테스트도 실제로 비싸지 않으므로 많은 작업을 원하지 않습니까? (다각형 가정)
Mattia

Ok modulo는 실제로 문제가 있지만 간단한 해결책입니다. 우리가 진정으로 얻는 것은 랜덤 P = 1 / 2 비트 0/1이므로, 우리가 얻는 것은 숫자의 균일 한 분포입니다. rand % 5를 수행하면 임의의 숫자가 6 또는 7을 취하면 1 또는 2에 매핑되어 1,2 주파수를 효과적으로 증가시켜 분포를 불균일하게 만듭니다. 이를 피하기 위해 매핑을 회전시키는 상태 머신과 같은 것이 필요합니다. 6,7은 1,2, 3,4, 5,0으로 매핑되고 계속됩니다. 우리는 그들이 올 때마다 6,7을 버릴 수도 있습니다. 어쨌든 그것은 라이브러리 구현 문제입니다.
FranG

-1

다른 접근 방식 :하지 마십시오.

대신 :

while (Segments.Count > 3)
{
    Segment A = Segments[Segments.Count - 2];
    Segment B = Segments[Segments.Count - 1];
    Segment C = new Segment(B.End, A.Start);
    Triangle T = new Triangle(A, B, C);
    Segments[Segments.Count - 2] = C;
    Segments.RemoveAt(Segments.Count - 1);
    if (B is inside the new shape Segments)
        Area -= T.Area;
    else
        Area += T.Area;
}
Area += new Triangle(Segments[0], Segments[1], Segments[2]).Area;

기본적으로 삼각형을 제거하십시오. 삼각형의 면적은 간단하고 그렇게함으로써 나머지의 세그먼트 수를 1 씩 줄였습니다. 남은 것이 삼각형이 될 때까지 반복하십시오.


2
Gauss의 신발 끈 공식은 계산 횟수의 절반 또는 3 분의 1을 나타내는 축약 형입니다. 그것을 해결하십시오.
Pieter Geerkens
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.