폴리곤 팽창 / 팽창 (오프셋, 버퍼링) 알고리즘


202

다각형을 어떻게 "부 풀리게"합니까? 즉, 나는 이것과 비슷한 것을하고 싶다 :

대체 텍스트

요구 사항은 새로운 (팽창 된) 다각형의 가장자리 / 점이 모두 기존 (원래의) 다각형과 같은 일정한 거리에 있어야한다는 것입니다 (예제에서는 그렇지 않습니다. 지금은 잊어라;)).

내가 찾고있는 것에 대한 수학적 용어는 실제로 안쪽 / 바깥 쪽 다각형 오프셋 입니다. 이것을 지적하기 위해 발린 +1. 다른 이름은 다각형 버퍼링 입니다.

내 검색 결과 :

다음은 몇 가지 링크입니다.


17
이것은 전혀 사소한 질문이 아닙니다. 디플레이션 / 인플레이션이 작 으면 심각한 일이 발생하지 않지만 어느 시점에서 정점이 사라집니다. 아마도 이것은 이전에 수행되었으므로 다른 사람의 알고리즘을 사용하고 자신의 알고리즘을 작성하지 마십시오.
Martijn

1
실제로, 다각형이 (위의 예에서와 같이) 시작하기 위해 오목한 경우 순진 알고리즘이 자체 교차 '다각형'을 만들고자하는 시점에서 어떤 일이 발생해야하는지 결정해야합니다.
AakashM

예, 주된 문제는 다각형의 오목한 부분입니다. 이것이 복잡성이있는 곳입니다. 나는 여전히 특정 정점을 제거해야 할 때를 계산하는 것이 그렇게 문제가되지 않아야한다고 생각합니다. 주요 질문은 이것이 어떤 종류의 점근 적 복잡성을 요구하는지입니다.
Igor Brejc

안녕하세요, 3D로 수행해야한다는 점을 제외하고는 내 문제이기도합니다. 논문 arxiv.org/pdf/0805.0022.pdf에 설명 된 3 차원 다면체의 직선 골격 접근법에 대한 대안이 있습니까?
stephanmg

답변:


138

나는 잠시 내 자신의 언급 거라고 생각 다각형 클리핑 및 상쇄 라이브러리 - 클리퍼를 .

Clipper 는 주로 다각형 클리핑 작업을 위해 설계 되었지만 다각형 오프셋도 수행합니다. 라이브러리는 Delphi, C ++ 및 C #으로 작성된 오픈 소스 프리웨어 입니다 . 무료 라이센스와 상용 응용 프로그램 모두에서 무료로 사용할 수 있는 매우 강화 된 Boost 라이센스가 있습니다.

다각형 오프셋은 사각형, 원형 ​​및 연귀의 세 가지 오프셋 스타일 중 하나를 사용하여 수행 할 수 있습니다.

다각형 오프셋 스타일


2
아주 멋지다! 2 년 전 어디에 있었습니까? :) 결국 나는 내 자신의 오프셋 논리를 구현해야했고 (많은 시간을 잃었다). BTW 다각형 오프셋에 어떤 알고리즘을 사용하고 있습니까? 나는 잔디 불을 사용했습니다. 다각형의 구멍을 처리합니까?
Igor Brejc

2
2 년 전 까다로운 라이센스 문제가 발생하지 않은 다각형 클리핑에 대한 적절한 솔루션을 찾고있었습니다. :). 모든 모서리에 대해 단위 법선을 생성하여 모서리 오프셋을 수행합니다. 겹친 교차점의 방향이 다각형의 방향과 반대이므로 모서리 조인은 다각형 클리퍼로 정리됩니다. 구멍은 자체 교차 다각형과 같이 가장 확실하게 처리됩니다. 유형이나 수에는 제한이 없습니다. "권선 번호 계산을 통한 다각형 오프셋"도 참조하십시오. me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf
Angus Johnson

우와! 두 번째로이 질문이 "잊어졌다"고 생각하지 마십시오! 지난주에 여기를 보았습니다. 무리 감사!
Chris Burt-Brown


5
이 작업을 수행하려는 사람은 GEOS를 사용하는 것이 좋습니다. 파이썬을 사용하는 경우 GEOS의 래퍼 인 Shapely가 있습니다. 정말 예쁜 예 : toblerity.github.com/shapely/manual.html#object.buffer
pelson

40

찾고있는 다각형 을 계산 기하학에서 안쪽 / 바깥 쪽 오프셋 다각형 이라고 하며 직선 골격 과 밀접한 관련이 있습니다.

다음은 복잡한 다각형에 대한 여러 오프셋 다각형입니다.

그리고 이것은 다른 다각형의 직선 골격입니다.

다른 의견에서도 지적했듯이 다각형을 얼마나 "팽창 / 팽창"시킬 계획인지에 따라 출력에 다른 연결성을 가질 수 있습니다.

계산 관점에서 : 일단 직선 골격을 가지면 오프셋 다각형을 비교적 쉽게 구성 할 수 있어야합니다. 공개 소스 및 (비 상업용 무료) CGAL 라이브러리에는 이러한 구조를 구현하는 패키지가 있습니다. CGAL을 사용하여 오프셋 다각형을 계산하려면 이 코드 예제 를 참조하십시오 .

패키지 매뉴얼은 당신이 CGAL를 사용하지 않을 경우에도 이러한 구조를 구성하는 방법에 대한 시작점 당신에게 좋은를 제공하고, 수학적 정의와 속성을 사용하여 논문에 대한 참조를 포함한다 :

CGAL 매뉴얼 : 2D 직선 스켈레톤 및 다각형 오프셋


12

이런 종류의 것들에 대해서는 보통 JTS를 사용 합니다. 데모 목적으로 JSTS (JavaScript port of JTS) 를 사용하는 이 jsFiddle 을 작성했습니다 . 필요한 좌표를 JSTS 좌표로 변환하면됩니다.

function vectorCoordinates2JTS (polygon) {
  var coordinates = [];
  for (var i = 0; i < polygon.length; i++) {
    coordinates.push(new jsts.geom.Coordinate(polygon[i].x, polygon[i].y));
  }
  return coordinates;
}

결과는 다음과 같습니다.

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

추가 정보 : 나는 일반적으로지도에 그려진 다각형 (리플렛 또는 Google지도)에 반경으로 경계를 설정하기 위해이 유형의 팽창 / 수축 (내 목적에 약간 수정)을 사용합니다. (lat, lng) 쌍을 JSTS 좌표로 변환하면 다른 모든 항목이 동일합니다. 예:

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


9

당신이 원하는 것 같아요.

  • 정점에서 시작하여 인접한 가장자리를 따라 시계 반대 방향으로 향합니다.
  • 모서리를 기존 모서리 d의 "왼쪽" 에 떨어진 새 평행 모서리로 교체하십시오 .
  • 모든 모서리에 대해 반복하십시오.
  • 새로운 꼭지점을 얻기 위해 새로운 모서리의 교차점을 찾으십시오.
  • 교차 다각형이되었는지 감지하고 그에 대한 조치를 결정하십시오. 교차점에 새로운 정점을 추가하고 오래된 정점을 제거하십시오. 인접하지 않은 모든 모서리 쌍을 비교하여 두 쌍의 정점 사이에 교차점이 있는지 확인하는 것보다 이것을 감지하는 더 좋은 방법이 있는지 확실하지 않습니다.

결과 다각형은 정점에서 "충분한"기존 다각형으로부터 필요한 거리에 있습니다. 정점 근처 d에서 기존 다각형으로부터 떨어진 점 세트는 다각형이 아니므로 명시된 요구 사항을 충족시킬 수 없습니다.

이 알고리즘에 이름, 웹상의 예제 코드 또는 최종 최적화가 있는지는 모르지만 원하는 것을 설명한다고 생각합니다.


6

GIS 세계에서는이 작업에 네거티브 버퍼링을 사용합니다 : http://www-users.cs.umn.edu/~npramod/enc_pdf.pdf

JTS 라이브러리는 당신을 위해이 작업을 수행해야합니다. 버퍼 조작에 대한 문서를 참조하십시오. http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/operation/buffer/package-summary.html

대략적인 개요는 개발자 안내서를 참조하십시오 : http://www.vividsolutions.com/jts/bin/JTS%20Developer%20Guide.pdf


5

각 선은 평면을 "내부"및 "개요"로 분할해야합니다. 일반적인 내부 제품 방법을 사용하여 찾을 수 있습니다.

모든 선을 일정 거리만큼 바깥쪽으로 이동하십시오.

모든 인접 선 쌍 (선 세그먼트가 아닌 선)을 고려하고 교차점을 찾으십시오. 이들은 새로운 정점입니다.

교차하는 부분을 제거하여 새 정점을 정리하십시오. -여기 몇 가지 사례가 있습니다

(a) 사례 1 :

 0--7  4--3
 |  |  |  |
 |  6--5  |
 |        |
 1--------2

하나만 소비하면 다음과 같은 결과를 얻습니다.

0----a----3
|    |    |
|    |    |
|    b    |
|         |
|         |
1---------2

7과 4가 겹칩니다.이 경우이 점과 그 사이의 모든 점이 제거됩니다.

(b) 사례 2

 0--7  4--3
 |  |  |  |
 |  6--5  |
 |        |
 1--------2

두 개를 소비하면 다음과 같은 결과를 얻습니다.

0----47----3
|    ||    |
|    ||    |
|    ||    |
|    56    |
|          |
|          |
|          |
1----------2

이 문제를 해결하려면 각 선분에 대해 후자의 선분과 겹치는 지 확인해야합니다.

(c) 사례 3

       4--3
 0--X9 |  |
 |  78 |  |
 |  6--5  |
 |        |
 1--------2

이것은 1로 소비됩니다. 이것은 사례 1의 경우보다 일반적인 경우입니다.

(d) 사례 4

case3과 동일하지만 2만큼 소비됩니다.

실제로 사례 4를 처리 할 수있는 경우 다른 모든 사례는 선이나 정점이 겹치는 특수한 경우입니다.

경우 4를 수행하기 위해 정점 스택을 유지합니다. 후행과 겹치는 선을 찾을 때 푸시하고 후자의 선을 가져올 때 팝합니다. -볼록 껍질에서하는 것과 같습니다.


이것에 대한 psedo 알고리즘을 알고 있습니까?
EmptyData

5

다음은 대체 솔루션입니다. 더 좋아하는지 확인하십시오.

  1. DO가 삼각 측량을 , 그것은 들로네가 될 필요가 없습니다 - 어떤 삼각 측량 할 것입니다.

  2. 각 삼각형을 부 풀리십시오-이것은 사소한 것입니다. 시계 반대 방향으로 삼각형을 저장하는 경우 선을 오른쪽으로 이동하고 교차로를 수행하십시오.

  3. 수정 된 Weiler-Atherton 클리핑 알고리즘을 사용하여 병합


삼각형을 정확히 어떻게 팽창 시키나요? 출력은 삼각 분할에 의존합니까? 이 방법을 사용하면 다각형을 축소 할 때 사례를 처리 할 수 ​​있습니까?
balint.miklos

이 방법이 다각형 인플레이션에 실제로 효과가 있습니까? 다각형의 오목한 부분이 팽창되어 일부 정점이 제거 될 때 발생하는 현상입니다. 문제는 폴리 다음에 삼각형에 어떤 일이 생겼는지 볼 때입니다. 인플레이션의 경우 삼각형이 팽창하지 않고 왜곡됩니다.
Igor Brejc

1
Igor : Weiler-Atherton 클리핑 알고리즘은 "일부 정점을 제거해야합니다"경우를 올바르게 처리 할 수 ​​있습니다.
J-16 SDiZ

@balint : 삼각형을 부 풀리게 팽창 시키십시오 : vertrex를 정상적인 순서로 저장하면 오른쪽은 항상 "외부"입니다. 그 선분을 선으로 취급하고 바깥쪽으로 옮기고 상호 작용을 찾으십시오. 새로운 정점입니다. 삼각 측량 자체의 경우 두 번째로 들로네 삼각 측량 (Delaunay Triangulation)이 더 나은 결과를 제공 할 수 있습니다.
J-16 SDiZ

4
이 접근법은 쉽게 나쁜 결과를 줄 수 있다고 생각합니다. 대각선을 사용하여 사변형을 삼각형으로 한 간단한 예에서도 마찬가지입니다. 확대 된 두 개의 삼각형의 경우 : img200.imageshack.us/img200/2640/counterm.png 그리고 그들의 조합은 당신이 찾고있는 것이 아닙니다. 이 방법이 어떻게 유용한 지 모르겠습니다.
balint.miklos

3

클리퍼 라이브러리에 대한 앵거스 존슨에게 큰 감사를드립니다. 클리퍼 홈페이지 ( http://www.angusj.com/delphi/clipper.php#code) 에서 클리핑 작업을 수행하기위한 좋은 코드 샘플이 있지만 다각형 오프셋에 대한 예제는 보지 못했습니다. 그래서 코드를 게시하면 누군가에게 유용하다고 생각했습니다.

    public static List<Point> GetOffsetPolygon(List<Point> originalPath, double offset)
    {
        List<Point> resultOffsetPath = new List<Point>();

        List<ClipperLib.IntPoint> polygon = new List<ClipperLib.IntPoint>();
        foreach (var point in originalPath)
        {
            polygon.Add(new ClipperLib.IntPoint(point.X, point.Y));
        }

        ClipperLib.ClipperOffset co = new ClipperLib.ClipperOffset();
        co.AddPath(polygon, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);

        List<List<ClipperLib.IntPoint>> solution = new List<List<ClipperLib.IntPoint>>();
        co.Execute(ref solution, offset);

        foreach (var offsetPath in solution)
        {
            foreach (var offsetPathPoint in offsetPath)
            {
                resultOffsetPath.Add(new Point(Convert.ToInt32(offsetPathPoint.X), Convert.ToInt32(offsetPathPoint.Y)));
            }
        }

        return resultOffsetPath;
    }

2

추가 옵션 중 하나는 boost :: polygon 을 사용 하는 것입니다. 설명서에는 다소 부족하지만 실제로 버퍼링을 구현 하는 메서드 resizebloat오버로드 된 +=연산자 도 있습니다 . 예를 들어 다각형 (또는 다각형 집합)의 크기를 특정 값만큼 늘리는 것은 다음과 같이 간단 할 수 있습니다.

poly += 2; // buffer polygon by 2

부스트 :: 폴리곤으로 정수 좌표 만 지원하기 때문에 어떻게해야합니까? 일반 (부동 소수점 좌표) 다각형이 있고 확장하고 싶습니다. 어떻게해야합니까?
David Doria

@DavidDoria : 좌표에 필요한 해상도 / 정확도 및 동적 범위에 따라 다르지만 적절한 배율로 32 비트 또는 64 비트 int를 사용할 수 있습니다. 우연히 나는 실수로 부스트 좌표가있는 boost :: polygon을 사용했으며 정상적으로 작동 하는 것처럼 보이지만 100 % 강력하지는 않습니다 (문서는 그것에 대해 경고합니다!).
Paul R

나는 "대부분 일할 것이다":) 괜찮습니다. 나는 이것을 시도했다 : ideone.com/XbZeBf 그러나 컴파일되지 않는다-어떤 생각?
David Doria

나는 분명히 잘못된 것을 보지 못했지만 제 경우에는 직선형 전문화 (polygon_90)를 사용했기 때문에 차이가 있는지 모르겠습니다. 그래도 몇 년이 지 났어요.
Paul R

좋아-이제 다시 돌아옵니다 . 개별 다각형이 아닌 +=다각형 세트 만 사용할 수 있습니다 . std :: vector of polygons로 사용해보십시오. 물론 벡터에는 다각형이 하나만 있으면됩니다.
Paul R

1

@ JoshO'Brian의 조언 rGeos에 따르면 R언어로 된 패키지 가이 알고리즘을 구현 하는 것으로 보입니다 . 참조하십시오 rGeos::gBuffer.


0

사용할 수있는 몇 가지 라이브러리가 있습니다 (3D 데이터 세트에도 사용 가능).

  1. https://github.com/otherlab/openmesh
  2. https://github.com/alecjacobson/nested_cages
  3. http://homepage.tudelft.nl/h05k3/Projects/MeshThickeningProj.htm

알고리즘을 더 자세히 이해하기 위해 이러한 라이브러리에 해당하는 서적을 찾을 수도 있습니다.

마지막 것은 가장 의존성이 적으며 독립적이며 .obj 파일에서 읽을 수 있습니다.

소원, 스테판


0

간단한 지오메트리를 사용합니다 : 벡터 및 / 또는 삼각법

  1. 각 모서리에서 중간 벡터와 중간 각도를 찾으십시오. 중간 벡터는 모서리의 가장자리로 정의 된 두 단위 벡터의 산술 평균입니다. 중간 각도는 가장자리로 정의 된 각도의 절반입니다.

  2. 각 모서리에서 d의 양만큼 다각형을 확장 (또는 축소)해야하는 경우 새로운 코너 포인트를 얻으려면 d / sin (midAngle)만큼 나가야합니다.

  3. 모든 구석에 이것을 반복하십시오

*** 당신의 지시에주의하십시오. 코너를 정의하는 세 지점을 사용하여 CounterClockWise 테스트를 수행하십시오. 어느 방향으로 나가는 지 알아 내야합니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.