31

저는 비교적 단순한 해결책이 있어야한다고 생각하는 계산 기하학 문제가 있습니다. 그러나 나는 그것을 이해할 수 없습니다.선분 집합의 볼록하지 않은 선체를 결정하십시오.

여러 선분으로 정의 된 영역의 비 볼록 윤곽을 결정해야합니다.

다양한 비 convex 선체 알고리즘 (예 : 알파 셰이프)을 알고 있지만 대부분의 경우 선분이 고유 한 솔루션을 정의하기 때문에 완전히 일반적인 알고리즘이 필요하지 않습니다.


@ Jean-FrançoisCorbett이 지적한 바와 같이, 여러 가지 해결책이있는 경우가 있습니다. 나는 분명히 내 정의에 대해 더 생각할 필요가있다.

그러나 내가하려는 것은 리버스 엔지니어링이며 독점적 인 파일 형식을 사용하므로 자신과 다른 사람이 수집 한 데이터에 대한 기본 분석을 실행할 수 있습니다. 파일 형식은 간단하지만 경계를 정의하는 알고리즘을 결정하는 것은 상당히 어렵습니다.

고유하지 않은 솔루션으로 이어질 수있는 많은 경우를두면 문제의 소프트웨어가 경고없이 충돌하거나 자동으로 파일을 읽지 못하게됩니다.

따라서 여러 솔루션이있는 경우 수용 가능한 솔루션 중 하나를 생성하거나 여러 솔루션이 있다고 판단 할 수 있습니다.


문제 정의 :

다각형의 윤곽은 세그먼트의 교차해서는 안 및 세그먼트 '모든 엔드 포인트에 합류 라인을 형성한다. 모든 세그먼트는 다각형의 경계 내부 또는 경계를 따라 위치해야합니다. 윤곽선에서 끝점을 두 번 이상 사용할 수 없습니다 (다각형을 닫아야하는 소프트웨어 라이브러리의 끝에 첫 번째 점을 추가하여 다각형을 "닫음"무시).

이 기준을 충족하는 솔루션이 여러 개인 경우 해당 솔루션 중 하나를 사용해도됩니다. (그것은 솔루션은 고유하지 않은시기를 결정 할 수 있도록 좋은 것입니다, 그러나 이것은 엄격하게 필요하지 않습니다.)


예 : 예를 들어

, 나는이 라인을 따라 뭔가를 : Segments Defining the Area

그리고 나는 다음과 같은 영역의 윤곽을 싶습니다 Desired Outline

또한 교차하지 않는 세그먼트에 대한 작동합니다. 예 : enter image description here

enter image description here 나는 생각 (?) 기준 개요 이전에 따라 각각의 경우에 고유 한 솔루션이있다. (편집 : @ Jean-FrançoisCorbett이 지적했듯이 일반적으로 유일한 해결책은 없습니다. 그러나 여전히 받아 들일 수있는 솔루션 중 하나를 생성하는 알고리즘에 관심이 있습니다.)

테스트 케이스

테스트 케이스를 들어

, 여기에 위의 수치를 생성하는 코드입니다. 저는 여기 파이썬을 사용하고 있습니다,하지만 질문은 언어에 구애받지 않습니다.

import matplotlib.pyplot as plt 

def main(): 
    test1() 
    test2() 
    plt.show() 

def test1(): 
    """Intersecting segments.""" 
    segments = [[(1, 1), (1, 3)], 
       [(3.7, 1), (2, 4)], 
       [(2, 0), (3.7, 3)], 
       [(4, 0), (4, 4)], 
       [(4.3, 1), (4.3, 3)], 
       [(0, 2), (6, 3)]] 

    desired_outline = [segments[0][0], segments[5][0], segments[0][1], 
         segments[1][1], segments[2][1], segments[3][1], 
         segments[4][1], segments[5][1], segments[4][0], 
         segments[3][0], segments[1][0], segments[2][0], 
         segments[0][0]] 

    plot(segments, desired_outline) 

def test2(): 
    """Non-intersecting segments.""" 
    segments = [[(0, 1), (0, 3)], 
       [(1, 0), (1, 4)], 
       [(2, 1), (2, 3)], 
       [(3, 0), (3, 4)]] 

    desired_outline = [segments[0][0], segments[0][1], segments[1][1], 
         segments[2][1], segments[3][1], segments[3][0], 
         segments[2][0], segments[1][0], segments[0][0]] 

    plot(segments, desired_outline) 


def plot(segments, desired_outline): 
    fig, ax = plt.subplots() 
    plot_segments(ax, segments) 
    ax.set_title('Segments') 

    fig, ax = plt.subplots() 
    ax.fill(*zip(*desired_outline), facecolor='gray') 
    plot_segments(ax, segments) 
    ax.set_title('Desired Outline') 

def plot_segments(ax, segments): 
    for segment in segments: 
     ax.plot(*zip(*segment), marker='o', linestyle='-') 
    xmin, xmax, ymin, ymax = ax.axis() 
    ax.axis([xmin - 0.5, xmax + 0.5, ymin - 0.5, ymax + 0.5]) 

if __name__ == '__main__': 
    main() 

아이디어가 있으십니까?

내가 재현하려는 소프트웨어가 "내부"좌표계 (예 : x-primey-prime이있는 좌표계)에서 방사형 스윕 알고리즘을 사용한다고 의심되기 시작했습니다. 포인트의 확산에 의해 정의 된 주축. 이것은 문제를보다 "원형"으로 만든다.) 그러나, 많은 경우 아웃 라인이 선분과 교차하는 솔루션을 생성한다. 이것을 감지하고 거기에서 무차별 대입하는 것은 쉽지만 확실하게 더 좋은 방법이 있습니까?

+0

"막대가 고유하게 솔루션을 정의합니다"라고 말하면 막대가 모두 최종 다각형 안에 있어야한다는 의미입니까? –

+0

예! 정보에 그 정보를 추가해야했습니다. 감사! –

+0

Mark de Berg와 CGAL 라이브러리 "Computational Geometry"책보기 효율적인 알고리즘을 찾을 수있을 것입니다. – mitch

답변

16
  1. 안전한 시작 지점을 지정하십시오. 예 : 최대 x를 가지는 엔드 포인트
  2. 3 월 라인 세그먼트를 따라.
  3. 교차로가 만났을 때 항상 왼쪽으로 돌면서이 새 세그먼트를 따라 행진하십시오.
  4. 엔드 포인트가 발생하면 기록하십시오. 2.
  5. 출발 지점으로 돌아 왔을 때 그만하십시오. 이제 기록 된 끝점 목록이 오목한 선체의 정점 순서 목록을 구성합니다.

NB : 다른 선분과 교차하지 않는 "자유롭게 떠 다니는"외곽선 세그먼트가 있으면 실패합니다. 그러나 "이 막대는 솔루션을 고유하게 정의합니다"라고 지정하면 실패 조건을 배제합니다. (외곽 세그먼트가 가능한 두 개의 고유 한 솔루션을합니다.)

편집 ... 또는 오히려, 외곽 세그먼트 이 개 독특한 솔루션을 가능하게 - 정확한 레이아웃에 따라 달라집니다. 증거 : 아래에 내가 추가 한 노란색 세그먼트가 두 가지 솔루션을 가능하게하는 예가 나와 있습니다 (파란색과 회색 끔찍한 손으로 그린 ​​선). 노란색 세그먼트가 지금 그려지는 방향에 수직으로 향하게 했습니까? 단 하나의 솔루션 만 가능합니다. 문제가 제대로 정의되지 않은 것 같습니다. 세그먼트 컬렉션은 "매우 오목한"이면 엔드 세그먼트중인 더미 은둔 모서리에 자리 잡고있는 경우

enter image description here

EDIT 사실이 아니라, 즉 실패 할 수있다. 아래 그림에서 검정색 세그먼트를 추가했습니다. 내 알고리즘이 다른 끝점 (점선 회색 선)에 끝점을 불법적으로 연결합니다. 나는 다른 사람들이 그것을 쌓기를 원할 때를 대비해 나의 대답을 남겨 둘 것이다.는 심지어 "아주 오목"경우에,이 솔루션은 확실히 당신에게 적절한 순서에 오목 선체의 모든 포인트을 줄 것이다하지만이있을 수 있습니다 :

편집이 좀 더 생각을주고 나서 검은 색과 같은 부적절한 점들로 산재 해있다. 따라서 이 많아서 점이 너무 많습니다.

대답은 물론, 가지 치기를하는 것입니다. 검은 색과 같이 여러 개의 연속적인 "recluse points"를 가질 수 있다면 상당히 복잡한 가지 치기가 될 것이므로 스마트 알고리즘을 염두에 두지 마십시오.그러나 눈이 멀고 무차별 한 세력조차도 실현 가능할 수 있습니다. 각 점은 합격 또는 불합격 (부울) 일 수 있으므로 N 오목한 선체에 올바르게 정렬 된 후보 점이있는 경우 검사 할 가능성은 2^N입니다. 이것은 방법 가능성이 순열의 원래 문제에 대한 무력보다 가능성이 적습니다 SUM of (n!/(n-k)!) for k=1:(n-1) 가능성 (용서 내 표기법). 따라서이 알고리즘은 문제를 상당히 줄입니다.

나는 이것이 갈 길이라고 생각합니다.

enter image description here

+0

니스! 나는 그것을 조금 생각하고 싶다. 그러나 나는 네가 그것을 못 박았다고 생각한다. –

+0

* "내 알고리즘이 다른 끝점 (점선 회색 선)에 끝점을 합법적으로 연결합니다."* - 간단하게 결과 선이 막대 또는 기존 선을 넘지 않도록하십시오. –

+0

두 번째 생각에서 실제로 교차하지 않는 세그먼트의 경우에 작동해야합니다. (사실, 내 데이터를 살펴본 후에는 이전에 눈치 채지 못했던 보통의 경우입니다.) 이전과 동일한 기준에 따라 여전히 고유 한 솔루션이 있습니다 (가능한 한 멀리 말할 수 있음). 막대기로 구성되며 끝점으로 구성됩니다). 답변을 수락하는 것에 대해 미안합니다! –

2

아니 완전히 구체화 아웃 생각하지만, 어쨌든 : 당신은 시작한다고 가정 w 볼록 선체의 원형 스윕 알고리즘 (/ 위치를 정렬 한 후 과정에서 자신의 각도로 포인트 중심점). 모든 포인트가이 선체에서 끝나면 끝난 것입니다. 그렇지 않다면이 점들을 포함하기 위해 선체를 "조여야"합니다. 이 지점들 각각은 볼록 선체의 후보 였고, 볼록 함을 깨뜨렸기 때문에 제거되었습니다. 때로는 (첫 번째 예에서 맨 위의 자주색 점과 마찬가지로) 단순히 그 부분을 그대로 둘 수 있습니다. 선체의 새 세그먼트가 아래쪽의 녹색에서 아래쪽의 자주색으로 첫 번째 예를 들어, 아쿠아 포인트가 녹색보다 먼저 처리되었다고 가정하면, 수정 사항은 좀 더 복잡해집니다. (그리고 내가 뜯어 먹지 않은 부분은 최신 편집에서 언급 한 부분입니다).

관련 문제