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


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.