2D 점 세트의 볼록 껍질 찾기


20

손톱을 나무 판에 망치로 감고 고무 밴드를 감싸면 볼록 껍질이 생깁니다 .

여기에 이미지 설명을 입력하십시오

당신의 임무는, 당신이 그것을 받아들이기로 결정한다면, 주어진 2D 포인트 세트의 볼록 껍질 을 찾는 것 입니다.


몇 가지 규칙 :

  • 함수로 작성하십시오. 원하는 포인트 형식의 목록 좌표가 인수입니다.
  • 출력은 시계 방향 또는 반 시계 방향으로 나열된 볼록 껍질의 지점 목록이어야합니다.
  • 출력 목록은 각 점의 좌표를 명확하게 구별 할 수있는 합리적인 형식 일 수 있습니다. (예를 들어 1 개의 희미한 목록이 아님 {0.1, 1.3, 4, ...})
  • 볼록 껍질 선분에서 세 개 이상의 점이 정렬되면 두 극단 만 출력에 유지되어야합니다.

샘플 데이터 :

샘플 0

입력:

{{1, 1}, {2, 2}, {3, 3}, {1, 3}}

산출:

{{3, 3}, {1, 3}, {1, 1}}

Mathematica 그래픽 (그림은 단지 예시 일뿐입니다)

샘플 1

입력:

{{4.4, 14}, {6.7, 15.25}, {6.9, 12.8}, {2.1, 11.1}, {9.5, 14.9}, 
 {13.2, 11.9}, {10.3, 12.3}, {6.8, 9.5}, {3.3, 7.7}, {0.6, 5.1}, {5.3, 2.4}, 
 {8.45, 4.7}, {11.5, 9.6}, {13.8, 7.3}, {12.9, 3.1}, {11, 1.1}}

산출:

{{13.8, 7.3}, {13.2, 11.9}, {9.5, 14.9}, {6.7, 15.25}, {4.4, 14}, 
 {2.1, 11.1}, {0.6, 5.1}, {5.3, 2.4}, {11, 1.1}, {12.9, 3.1}}

Mathematica 그래픽

샘플 2

입력:

{{1, 0}, {1, 1}, {1, -1}, {0.68957, 0.283647}, {0.909487, 0.644276}, 
 {0.0361877, 0.803816}, {0.583004, 0.91555}, {-0.748169, 0.210483}, 
 {-0.553528, -0.967036}, {0.316709, -0.153861}, {-0.79267, 0.585945},
 {-0.700164, -0.750994}, {0.452273, -0.604434}, {-0.79134, -0.249902}, 
 {-0.594918, -0.397574}, {-0.547371, -0.434041}, {0.958132, -0.499614}, 
 {0.039941, 0.0990732}, {-0.891471, -0.464943}, {0.513187, -0.457062}, 
 {-0.930053, 0.60341}, {0.656995, 0.854205}}

산출:

{{1, -1}, {1, 1}, {0.583004, 0.91555}, {0.0361877, 0.803816}, 
 {-0.930053, 0.60341}, {-0.891471, -0.464943}, {-0.700164, -0.750994}, 
 {-0.553528, -0.967036}}

Mathematica 그래픽

표준 코드 골프 규칙이 적용됩니다. 임시 지오메트리 라이브러리가 없습니다. 더 짧은 코드가 승리합니다.

편집 1

여기서는 MatLab 이나 Mathematica 와 같은 볼록 껍질 파인더 사전 프로그래밍 루틴 아닌 알고리즘 답변을 찾고 있습니다.

편집 2

답변 의견 및 추가 정보 :

  1. 입력 목록에 적합한 최소 개수의 점이 포함되어 있다고 가정 할 수 있습니다. 그러나 정렬 된 (하위) 세트를 올바르게 처리해야합니다.
  2. 입력 목록에서 반복되는 점을 찾을 수 있습니다
  3. 최대 포인트 수는 사용 가능한 메모리에 의해서만 제한되어야합니다
  4. "부동 소수점"다시 : 샘플에 제공된 것과 같은 소수 좌표를 사용하여 입력 목록을 처리 할 수 ​​있어야합니다. 당신은 수있는 부동 소수점 표현을 사용하여 해당 작업을 수행

.


2
MATLAB 이 이길 것으로 예상합니다 .
Paul R

적어도 3 점이 있다고 가정 할 수 있습니까? 포인트가 서로 다르다고 가정 할 수 있습니까? 부동 소수점 좌표를 지원해야합니까?
피터 테일러

@PeterTaylor 예는 마지막 답변이 사실임을 나타냅니다
John Dvorak

입력을 덮어 쓸 수 있습니까?
John Dvorak

공 선점을 일관되게 처리하는 데있어 문제는 반올림 문제입니다. 우리는 실수를 저지를 수 있어야합니다.
John Dvorak

답변:


2

루비, 168 자

C=->q{r=[]
f=m=q.sort[0]
t=-0.5
(_,_,t,*f=q.map{|x,y|a=x-f[0]
b=y-f[1]
[0==(d=a*a+b*b)?9:(-t+e=Math.atan2(b,a)/Math::PI)%2,-d,e,x,y]}.sort[0]
r<<=f)while
!r[1]||f!=m
r}

이 루비 코드는 선물 포장 알고리즘도 사용합니다. 이 함수 C는 점의 배열을 받아들이고 볼록 껍질을 배열로 반환합니다.

예:

>p C[[[4.4, 14], [6.7, 15.25], [6.9, 12.8], [2.1, 11.1], [9.5, 14.9], 
     [13.2, 11.9], [10.3, 12.3], [6.8, 9.5], [3.3, 7.7], [0.6, 5.1], [5.3, 2.4], 
     [8.45, 4.7], [11.5, 9.6], [13.8, 7.3], [12.9, 3.1], [11, 1.1]]]

[[5.3, 2.4], [11, 1.1], [12.9, 3.1], [13.8, 7.3], [13.2, 11.9], [9.5, 14.9], [6.7, 15.25], [4.4, 14], [2.1, 11.1], [0.6, 5.1]]

2

매스 매 티카 151

여전히 진행중인 작업

f = For[t = Sort@#; n = 1; l = Pi; a = ArcTan; c@1 = t[[1]],
       n < 2 || c@n != c@1, 
       n++,
      (l = a @@ (# - c@n); c[n + 1] = #) & @@
      t[[Ordering[Mod[a@## - l, 2 Pi] & @@ (#2 - #1) & @@@ Tuples@{{c@n}, t}, 1]]]] &

테스트 :

ClearAll[a, c, t];
s = {{1, 0}, {0.68957, 0.283647}, {0.909487, 0.644276}, {0.0361877, 0.803816}, 
     {0.583004, 0.91555}, {-0.748169, 0.210483}, {-0.553528, -0.967036}, 
     {0.316709, -0.153861}, {-0.79267, 0.585945}, {-0.700164, -0.750994}, 
     {0.452273, -0.604434}, {-0.79134, -0.249902}, {-0.594918, -0.397574}, 
     {-0.547371, -0.434041}, {0.958132, -0.499614}, {0.039941, 0.0990732}, 
     {-0.891471, -0.464943}, {0.513187, -0.457062}, {-0.930053, 0.60341}, 
     {0.656995, 0.854205}};
f@s
Show[Graphics@Line@Table[c@i, {i, n}], 
     ListPlot[{t, Table[c@i, {i, n}]}, 
     PlotStyle -> {PointSize[Medium], PointSize[Large]}, 
     PlotRange -> All]]

여기에 이미지 설명을 입력하십시오


1

CoffeeScript, 276 :

f=($)->z=$[0];e.r=Math.atan2(e.x-z.x,e.y-z.y)for e in $;$.sort((x,y)->(x.r>y.r)-(x.r<y.r));(loop(a=$[i-1]||$[$.length-1];b=$[i];c=$[i+1]||$[0];break if!b;s=(b.x-a.x)*(c.y-b.y)-(b.y-a.y)*(c.x-b.x);break if s<0||!s&&(a.x-b.x)*(b.x-c.x)<0;$.splice i,1))for i in [$.length-1..0];$

기능에 액세스 할 필요가없는 경우 제거 f=하여 두 개 이상의 문자를 제거하십시오 .

입력 / 출력은 단일 포인트 배열이며 각 포인트는 x,y속성에 의해 정의됩니다 . 입력 배열이 수정되고 반환됩니다 (후자가 필요하지 않은 경우 마지막 두 문자 제거).

나중에 설명을 추가 할 수 있습니다.

테스트 스위트 (oldIE에서는 작동하지 않음) :

alert JSON.stringify f({x:e[0], y:e[1]} for e in JSON.parse "
{{1, 1}, {2, 2}, ...}
".replace(/{/g,"[").replace(/}/g,"]"))

제안 된 테스트 환경 : http://coffeescript.org/


나는 그것을 시도하고 정답이 약간의 순열이라고 생각하는 동안 {{1, 1}, {2, 2}, {3, 3}, {1, 3}}돌아왔다[{"x" : 1, "y" : 1, "r" : 0}, {"x" : 1, "y" : 3, "r" : 0}, "x" : 2, "y" : 2, "r" : 0.78..}]{{3, 3}, {1, 3}, {1, 1}}
Dr. belisarius

@belisarius 문제가 때때로 잘못된 선체를 생성하는 점과 동일 선상에 표시됨
John Dvorak

@belisarius이 질문을 테스트 사례로 추가하십시오.
John Dvorak

그것은 지금 제대로 작동하는 것 같습니다 :)
Dr. belisarius

1

파이썬, 209 (205) (195)

from math import*
s=lambda(a,b),(c,d):atan2(d-b,c-a)
def h(l):
 r,t,p=[],pi/2,min(l)
 while 1:
    q=min(set(l)-{p},key=lambda q:(s(p,q)-t)%(2*pi));m=s(p,q);r+=[p]*(m!=t);p=q;t=m
    if p in r:return r

선물 포장 알고리즘을 사용합니다. 결과는 가장 왼쪽 지점에서 시작하여 시계 반대 방향으로 줄 바꿈됩니다.

예 : h([(1, 1), (2, 2), (3, 3), (1, 3)])반환[(1, 3), (1, 1), (3, 3)]


print출력을 얻기 위해 필요하지 않습니까?
Dr. belisarius

"출력"으로 함수의 출력을 의미한다고 생각했습니다. 함수가 결과를 반환하는 대신 인쇄하도록 하시겠습니까?
cardboard_box

나는 the output list can be in any reasonable format 가 충분히 명확 . 명시 적으로 언급해야한다고 생각하십니까?
Dr. belisarius

부동 소수점을 사용하는 경우 출력 지점이 입력 지점과 항상 일치하는 것은 아닙니다. 예를 들어 h([(0, 1), (0,1), (0.1 , 1)])나에게 준다[(0, 1), (0.10000000000000001, 1)]
벨리 사리우스 박사
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.