복잡한 다각형을 어떻게 결합합니까?


83

두 개의 다각형이 주어지면 :

POLYGON((1 0, 1 8, 6 4, 1 0))
POLYGON((4 1, 3 5, 4 9, 9 5, 4 1),(4 5, 5 7, 6 7, 4 4, 4 5))

합집합 (결합 다각형)은 어떻게 계산할 수 있습니까?

여기에 이미지 설명 입력

Dave의 예 에서는 SQL 서버를 사용하여 유니온을 생성하지만 코드에서 동일한 작업을 수행해야합니다. 실제 수학을 노출하는 모든 언어로 된 수학 공식 또는 코드 예제를 찾고 있습니다. 국가를 동적으로 지역으로 결합하는지도를 만들려고합니다. 여기에 관련 질문을했습니다. 지리적 형태 그룹화

답변:


69

이것은 아주 좋은 질문입니다. 얼마 전에 C #에서 동일한 알고리즘을 구현했습니다. 알고리즘은 두 다각형의 공통 윤곽을 구성합니다 (즉, 구멍없이 결합을 구성합니다). 여기있어.


골

1 단계. 다각형을 설명하는 그래프를 만듭니다.

입력 : 첫 번째 다각형 (n 포인트), 두 번째 다각형 (m 포인트). 출력 : 그래프. 정점-다각형 교차점.

교차로를 찾아야합니다. 두 다각형 [O (n * m)]의 모든 다각형면을 반복하고 교차점을 찾습니다.

  • 교차점이 없으면 정점을 추가하고 가장자리에 연결하기 만하면됩니다.

  • 교차점이 발견되면 길이별로 시작점까지 정렬하고 모든 꼭지점 (시작, 끝 및 교차점)을 추가 한 다음 (이미 정렬 된 순서대로) 가장자리에 연결합니다. 그래프

2 단계. 구성된 그래프 확인

그래프를 만들 때 교차점을 찾지 못한 경우 다음 조건 중 하나가 있습니다.

  1. Polygon1에 polygon2가 포함됨-polygon1 반환
  2. Polygon2에는 polygon1이 포함되어 있습니다-polygon2 반환
  3. Polygon1과 polygon2는 교차하지 않습니다. 다각형 1과 다각형 2를 반환합니다.

3 단계. 왼쪽 아래 꼭지점을 찾습니다.

최소 x 및 y 좌표 (minx, miny)를 찾습니다. 그런 다음 (minx, miny)와 다각형 점 사이의 최소 거리를 찾으십시오. 이 지점은 왼쪽 하단 지점이됩니다.

왼쪽 하단 지점

4 단계. 공통 윤곽을 만듭니다.

왼쪽 하단 지점에서 그래프를 횡단하고 다시 들어갈 때까지 계속합니다. 처음에는 모든 모서리를 방문하지 않은 것으로 표시합니다. 반복 할 때마다 다음 지점을 선택하고 방문한 것으로 표시해야합니다.

다음 점을 선택하려면 시계 반대 방향으로 최대 내부 각도가있는 모서리를 선택합니다.

두 벡터를 계산합니다 : 현재 가장자리에 대해 vector1과 다음 방문하지 않은 각 가장자리에 대해 vector2 (그림 참조).

벡터의 경우 다음을 계산합니다.

  1. 스칼라 곱 (내적). 벡터 사이의 각도와 관련된 값을 반환합니다.
  2. 벡터 곱 (교차 곱). 새로운 벡터를 반환합니다. 이 벡터의 z 좌표가 양수이면 스칼라 곱은 시계 반대 방향으로 직각을 제공합니다. 그렇지 않으면 (z 좌표가 음수 임) 벡터 사이의 각도를 스칼라 곱에서 360 각도로 계산합니다.

결과적으로 최대 각도를 가진 가장자리 (및 해당 다음 정점)를 얻습니다.

전달 된 각 정점을 결과 목록에 추가합니다. 결과 목록은 유니온 폴리곤입니다. 벡터

비고

  1. 이 알고리즘을 사용하면 여러 다각형을 병합하여 다각형 쌍을 반복적으로 적용 할 수 있습니다.
  2. 많은 베 지어 곡선과 선으로 구성된 경로가있는 경우 먼저이 경로를 병합해야합니다.

2
스칼라 곱을 비교하려면 벡터가 스칼라 곱을 계산하기 전에 정규화되어야한다고 언급해야한다고 생각합니다 (즉, 벡터 좌표를 길이로 나눕니다). 어쨌든이 답변에 감사드립니다.
eyalzba

이 알고리즘에 이름이 있습니까 아니면 자신이 만든 것입니까?
Andrés Oviedo

나는 어딘가를 읽을 수 있지만 지금은 기억하지 않는다 언제 어디서 =)
xtmq

참고 : 다른 다이어그램을 보여주는 구멍없는 다각형 결합을 참조하십시오 . 두 다각형이 겹치지 만 둘 다 덮지 않는 "구멍"이 있습니다. @xtmq의 주석에 따라이 알고리즘은 해당 구멍을 "채 웁니다"( 입력 다각형의 일부 가 아니더라도 ). 대신 해당 구멍을 구멍으로 "유지"하려면 (a) 구멍을 계산하고 (b) "구멍 세트"를 반환합니다. [일부 그래픽 시스템 / 모드에서 이러한 구멍은 출력 다각형 세트에 포함될 수 있습니다. 그릴 때, 정공 될 것이다]. ...
ToolmakerSteve

2
... "(a) 구멍 계산"을 수행하려면 "4 단계. 공통 윤곽 구성"에서 방문한 적이없는 지점을 찾습니다. 이 지점 중 하나를 사용하여 구멍을 "시작"하십시오. 주 출력 다각형에서 이미 사용하는 점을 제외하고 유사한 "윤곽"알고리즘을 수행합니다. 결과 다각형은 "구멍"입니다. 모든 점이 일부 다각형 또는 구멍에 포함될 때까지 반복합니다.
ToolmakerSteve



4

좋은 질문! 나는 전에 이것을 시도한 적이 없지만 지금 시도해 볼 것입니다.

첫째 :이 두 모양이 겹치는 부분을 알아야합니다. 이렇게하려면 다각형 A의 모든 가장자리를보고 교차하는 위치와 다각형 B의 가장자리를 볼 수 있습니다.이 예에서는 두 개의 교차점이 있어야합니다.

그런 다음 : 결합 모양을 만듭니다. A와 B의 모든 정점과 교차점을 가져온 다음 최종 모양에 포함 된 정점을 제외 할 수 있습니다. 이 점을 찾으려면 B 내부에있는 A의 정점과 A 내부에있는 B의 정점을 찾을 수있는 것처럼 보입니다.


네, 진짜 질문은 두 개의 추가 된 교차점을 어떻게 계산 할까요?
Pacerier 2013 년


2

BSP 트리를 사용하여 본 솔루션이 여기 에 설명되어 있습니다 .

기본적으로 다각형 B 내부 에있는 다각형 A 의 가장자리 (부분 가장자리 포함, BSP 트리를 사용하여 계산) 의 결합으로 교차를 설명합니다 . 그런 다음 A  /  B 를 ~ (~ A  / \ ~ B ) 로 정의 할 수 있습니다 . 여기서 ~는 다각형의 권선 반전을 나타내고 /는 합집합을 나타내고 / \는 교차를 나타냅니다.


2

이것은 매우 오래된 질문이지만 Boost의 Union_ 함수가 저에게 효과적 이었습니다.

아래 스 니펫을 참조하세요.

#include <iostream>
#include <vector>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>

#include <boost/foreach.hpp>


int main()
{
    typedef boost::geometry::model::polygon<boost::geometry::model::d2::point_xy<double> > polygon;

    polygon green, blue;

    boost::geometry::read_wkt(
        "POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))", green);

    boost::geometry::read_wkt(
        "POLYGON((5 5, 5 15, 15 15, 15 5, 5 5))", blue);

    std::vector<polygon> output;
    boost::geometry::union_(green, blue, output);

    int i = 0;
    std::cout << "green || blue:" << std::endl;
    BOOST_FOREACH(polygon const& p, output)
    {
        std::cout << i++ << ": " << boost::geometry::area(p) << std::endl;

        for (int i = 0; i < p.outer().size(); i++)
        {
            std::cout << p.outer().at(i).x() << " " << p.outer().at(i).y() << std::endl;
        }
    }



    return 0;
}

1
필요한 경우 다각형을 "수정"하는 것을 잊지 마십시오. stackoverflow.com/questions/22258784/…
anumi

1

국가를 그룹화 할 때 겹치지 않기를 바랍니다. 공유 된 정점을 찾는 상당히 순진한 알고리즘을 사용할 수 있습니다. 간단한보기는 한 다각형의 점을 반복하고 다른 다각형에 있는지 확인하는 것입니다. , 일치가 있는지 확인하기 위해 동일한 다음 또는 이전 지점을 공유합니다. 그런 다음 공유 정점을 제거하여 유니온을 만듭니다.


2
"국가를 그룹화 할 때 겹치지 않기를 바랍니다."... 모든 국가가 자신이나 이웃 국경에 동의하는 것은 아니지만 그렇게한다면 좋을 것입니다.
FrustratedWithFormsDesigner

2
@FrustratedWithFormsDesigner,하지만 대부분의지도 제작자는 분쟁 지역을 정치적 동맹에게 할당하거나 자체 권한으로 별도의 독립 체로 할당합니다. 그래서 내 알고리즘을 순진하다고 설명합니다 ...
Rowland Shaw


1

나는 같은 문제에 직면했고 다음과 같은 방법으로 문제를 해결했습니다.

Angus Johnson의 Clipper 라이브러리 (버전 6.4.2)의 C ++ 번역을위한 Cython 래퍼 https://github.com/fonttools/pyclipper

pc = pyclipper.Pyclipper()
def get_poly_union(polygons):
    pc.AddPaths(polygons, pyclipper.PT_SUBJECT, True)
    solution = pc.Execute(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
    return solution[0]

print_image = image.copy()
solution = get_poly_union(polygons_array) 
#polygons_array=[polygon,polygon,polygon, ...,polygon] and polygon=[point,point,point...,point]

cv2.drawContours(print_image, [np.asarray(solution)], -1, (0, 255, 0), 2)

plt.imshow(print_image)

Clipper는 여기에서 C ++로 직접 사용할 수 있습니다. angusj.com/delphi/clipper.php
Catskul
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.