irrregular polygon centroid (label point)를 찾기위한 알고리즘


13

Google지도에서 불규칙한 모양의 다각형에 대한 중심 (또는 레이블 포인트)을 찾아야합니다. 필자는 InfoWindows를 소포에 표시하고 있으며 InfoWindow를 표면에 고정시킬 수있는 장소가 필요합니다. 아래 이미지를 참조하십시오.

대체 텍스트 대체 텍스트

실제로 Google지도에만 필요한 것은 없으며이 지점을 자동으로 찾는 방법에 대한 아이디어 만 찾으면됩니다.

첫 번째 아이디어는 평균 위도와 경도를 취하고 다각형과 교차하는 점을 찾을 때까지 무작위로 배치하는 점을 찾아서 "거짓"중심을 찾는 것이 었습니다. 이미 포인트 인 다각형 코드가 있습니다. 이것은 나에게 "끔찍한"것처럼 보입니다.

ST_PointOnSurface (the_geom)와 같은 작업을 수행 할 수 없으므로 지오메트리를 출력하는 서버 측 코드에 액세스 할 수 없습니다.

답변:


6

빠르고 더러움 : "거짓"중심이 다각형에 없으면 해당 지점에 가장 가까운 정점을 사용하십시오.


나는 이것에 대해 생각하지 않았다. 이상적으로는 가장자리가 아닌 다각형 에서이 점을 원하지만 이것이 내가 다시 생각하는 것일 수 있습니다.
Jason

가장자리 점을 찾으면 해당 점을 중심으로 작은 정사각형을 다각형과 교차시킨 다음 교차점의 중심을 선택할 수 있습니다. 정사각형이 충분히 작 으면 내부 지점이 보장됩니다 (물론 가장자리에 매우 가깝습니다).
whuber

@Jason 실제 중심을 사용하면이 문제가 발생할 가능성이 적습니다. : 자바 스크립트에 신속하게 뭔가를 번역 너무 열심히해야하지 github.com/cartesiananalytics/Pipra/blob/master/src/...
댄디

내 솔루션 (가짜 중심에서 나온 광선)이 대부분의 시간 동안 작동하지만이 솔루션은 단순성과 최소한 가장자리를 발견하고 쉽게 이동할 수 있다는 사실 때문에 가장 효과적이라고 생각합니다. 약간의 노력으로 다각형 내부에 있어야합니다.
Jason

3

이것을보고 싶을 수도 있습니다 : http://github.com/tparkin/Google-Maps-Point-in-Polygon

제시 한 사례와 일치해야하는 레이 캐스팅 알고리즘을 사용하는 것 같습니다.

여기에 대한 블로그 게시물이 있습니다. http://appdelegateinc.com/blog/2010/05/16/point-in-polygon-checking/


서버 측에서이를 구현하려면 JTS (Java) 및 Geos (C) 모두이 기능을 구현합니다.
DavidF

예, 아마도 "계산 된"중심이 다각형 내에 있는지 여부를 결정하는 코드가 이미 추가되어 있어야합니다. 실제로 원하는 것은 다각형 내에 중심을 만드는 방법입니다.
Jason

3

(구형) ESRI 알고리즘은 질량 중심을 계산하고 다각형에 포함하기 위해 테스트 한 후 다각형 내에 놓일 때까지 수평으로 이동합니다. (프로그래밍 환경에서 사용 가능한 기본 작업에 따라 여러 가지 방법으로 수행 할 수 있습니다.) 이렇게하면 다각형의 시각적 중심에 상당히 가까운 레이블 지점이 생성되는 경향이 있습니다. 그림에서 시도해보십시오.


1

http://econym.org.uk/gmap 에서 인기있는 epoly 코드를 확장하여 문제를 해결했습니다 . 기본적으로 내가 한 일은 다음과 같습니다.

  • "거짓 중심"에서 시작하여 모든 모서리와 측면으로 연장되는 일련의 광선을 만듭니다 (총 8 개).
  • 점진적으로 각 광선 아래로 10,20,30 ... %를 만들고이 점이 원래 다각형에 있는지 확인합니다

아래의 확장 된 epoly 코드 :

google.maps.Polygon.prototype.Centroid = function() {
var p = this;
var b = this.Bounds();
var c = new google.maps.LatLng((b.getSouthWest().lat()+b.getNorthEast().lat())/2,(b.getSouthWest().lng()+b.getNorthEast().lng())/2);
if (!p.Contains(c)){
    var fc = c; //False Centroid
    var percentages = [0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]; //We'll check every 10% down each ray and see if we're inside our polygon
    var rays = [
        new google.maps.Polyline({path:[fc,new google.maps.LatLng(b.getNorthEast().lat(),fc.lng())]}),
        new google.maps.Polyline({path:[fc,new google.maps.LatLng(fc.lat(),b.getNorthEast().lng())]}),
        new google.maps.Polyline({path:[fc,new google.maps.LatLng(b.getSouthWest().lat(),fc.lng())]}),
        new google.maps.Polyline({path:[fc,new google.maps.LatLng(fc.lat(),b.getSouthWest().lng())]}),
        new google.maps.Polyline({path:[fc,b.getNorthEast()]}),
        new google.maps.Polyline({path:[fc,new google.maps.LatLng(b.getSouthWest().lat(),b.getNorthEast().lng())]}),
        new google.maps.Polyline({path:[fc,b.getSouthWest()]}),
        new google.maps.Polyline({path:[fc,new google.maps.LatLng(b.getNorthEast().lat(),b.getSouthWest().lng())]})
    ];
    var lp;
    for (var i=0;i<percentages.length;i++){
        var percent = percentages[i];
        for (var j=0;j<rays.length;j++){
            var ray = rays[j];
            var tp = ray.GetPointAtDistance(percent*ray.Distance()); //Test Point i% down the ray
            if (p.Contains(tp)){
                lp = tp; //It worked, store it
                break;
            }
        }
        if (lp){
            c = lp;
            break;
        }
    }
}
return c;}

여전히 약간 해 키지 만 작동하는 것 같습니다.


이 방법은 구불 구불 한 다각형의 경우 실패합니다. 예를 들어, 폴리 라인 {{0, 9}, {10, 20}, {9, 9}, {20, 10}, {9, 0}, {20, -10}, {9, -9}를 버퍼링하십시오. , {10, -20}, {0, -9}, {-10, -20}, {-9, -9}, {-20, -10}, {-9, 0}, {-20, 10}, {-9, 9}, {-10, 20}, {0,9}}를 1/2 미만으로 줄였습니다. 예를 들어 Dandy의 QAD 방법과 비교할 때 비효율적입니다.
whuber

1

이를 수행하는 또 다른 '더러운'알고리즘 :

  • 지오메트리의 경계 상자를 (Xmax, Ymax, Xmin, Ymin)

  • ( Xmin+rand*(Xmax-Xmin), Ymin+rand*(Ymax-Ymin) ) 지오메트리 내에서 임의의 점이 발견 될 때까지 반복 합니다 ( Google-Maps-Point-in-Polygon 사용 )


+2로 두 번째로 큰 타격을 입을 가능성이 있기 때문에 +1. 사용자를 성가 시게하지 않을 때마다 "무작위"를 재현 할 수있는 한 유효한 솔루션입니다. 유효한 포인트를 곧 얻지 못할 확률은 매우 적습니다. 특히 좋은 추측 포인트로 시작하는 경우 특히 그렇습니다.
Dandy

1
@ 댄디 : 사실, 어떤 경우에는 이것이 정말로 열악한 알고리즘 일 수 있습니다. 예를 들어 좁은 대각선 은색을 고려하십시오. 이들은 실제로 존재하며 (예를 들어, 길가의 긴 소포) 경계 상자의 0.1 % 미만 (때로는 훨씬 적음)을 쉽게 차지할 수 있습니다. 이 기술을 사용하여 이러한 다각형을 타격하는 것을 합리적으로 확신하려면 (95 % 확신) 약 3,000 회의 반복이 필요합니다.
whuber

@ Huber : 시작 위치가 잘못되면 완료하는 데 시간이 걸릴 수 있습니다. 가설 상 클릭의 95 %가 더 바람직한 형상에있을 것이라고 생각한다면 이것은 5 %의 문제 일뿐입니다. 또한 다른 GIS.se 질문과 마찬가지로 성능이 목표 인 경우 단일 솔루션이없는 경우 휴리스틱을 기반으로 전술을 변경하는 것이 가장 좋습니다. 3000 회 반복 할 이유가 없습니다. 당신은 항상 10 이후 QAD에 구제 할 수 있습니다. 나는 위치가 더 바람직 할 수 있기 때문에 이것을 몇 번 반복하여 시도해 볼 가치가 있다고 생각합니다.
Dandy

@ 댄디 : 그러나 QAD 솔루션의 문제는 무엇입니까? 원래 평가판 레이블 포인트에서 다각형의 일부 내부 버퍼에서 가장 가까운 정점으로 이동하여 조금 수정할 수도 있습니다. 여전히 QAD이지만 원래 피쳐의 내부 위치에 도달하도록 보장됩니다. BTW, 곧 구제 전략은 좋은 것입니다. 이처럼 임의의 프로브를 코딩 할 때마다 기능 영역의 비율과 경계 상자의 비율을 미리 계산하고이를 사용하여 예상되는 성공 시간을 찾은 다음, 사용자에게 시간이 오래 걸리는 경우 즉시 경고합니다.
whuber

@Whuber 면적 비율 휴리스틱은 면적을 계산할 때 중심을 계산하기 때문에 좋은 아이디어입니다. 내 QAD 솔루션의 문제는 가장자리에 있습니다. 내가 말한 것처럼 그 점을 선택하고 버퍼링하면 "작은"반지름이 좁은 부분의 길이보다 길 수 있습니다. 항상 코너 케이스가 있습니다. UI를 혼란스럽게 만들고 지오메트리를 모호하게하는 풍선을 만드는 것만으로도 고려해야 할 것이 많습니다. 가장 높은 정점 또는 가장 낮은 정점을 선택하는 것이 좋습니다.
Dandy

1

최근에 내부 위치를 엄격하게 선호한다는 명확한 설명을 고려하여 중간 축 변환에서 다각형의 경계에 있지 않은 점을 선택할 수 있습니다. (MAT에 대한 코드가없는 경우 다각형을 음으로 버퍼링하여 근사 할 수 있습니다. 이진 또는 secant 검색은 MAT의 일부에 가까운 작은 내부 다각형을 빠르게 생성하므로 경계의 아무 지점이나 사용하십시오.)


모서리가 관심있는 다각형의 내부에 있도록 지오메트리 모서리를 사용하는 것에 대해 말한 내용을 이해합니다. 이 가장자리 / 정점을 만드는 방법을 이해하지 못합니다. 내가 생각할 수있는 유일한 것은 관심 지점에서 선택한 점의 세그먼트 반대편 세그먼트에 수직 광선을 교차시켜 가상 삼각형을 만드는 것입니다. 이 두 점 사이의 중간 점이 가상 삼각형의 상단 일 수 있습니다.
Dandy

@ 댄디 : 그것의 중심에 도착합니다. GIS의 기본 기능에 따라 여러 가지 방법으로 문제를 해결할 수 있습니다. 예를 들어, 원래 길이와 양의 길이로 교차하는 광선을 발견 한 경우 해당 교차점은 선 세그먼트의 분리 된 결합이됩니다. 해당 세그먼트의 중심을 사용하십시오. 또 다른 방법은 피처의 어떤 지점부터 시작하는 것입니다 (바람직하게는 QED 방법이 달성 한 중간 부근), 중심에 작은 간단한 다각형 (예 : 정사각형)을 만들고 원래 피처와 교차하고 고유 한 연결을 선택하십시오 구성 요소 ...
whuber

(계속) ... 시작점을 포함하고 재귀 적으로 해당 구성 요소의 중심을 선택합니다. GIS를 사용하여 피쳐의 경계를 설명하는 정점 시퀀스를 반복 할 수있는 경우 사용할 수있는 방법이 많이 있습니다. 네거티브 버퍼가 지원되는 경우 최대 거리 내부 점 세트 (MAT의 하위 세트 인 "골격")를 반복적으로 찾을 수 있습니다. 이것은 약간 비싸지 만 프로그래밍하기가 쉽고 우수한 레이블 포인트를 생성합니다.
whuber

0

수직 (위도) 위치에만 중심을 사용하지 않는 이유는 무엇입니까? 그런 다음 해당 위도에서 평균 경도 선택하여 레이블을 가로로 배치 할 수 있습니다 . (이를 위해 특정 위도에서 다각형 가장자리의 경도 값을 찾아야하므로 문제가 발생하지 않아야합니다).

또한 U 모양과 더 복잡한 모양에주의하십시오. :) 아마도 정보 창이 방향을 향하고 있기 때문에 가장 오른쪽 경도 ​​쌍의 평균을 선택하십시오 (각 쌍은 다각형 조각에 해당합니다)?

이것으로 위치를 좀 더 제어 할 수 있습니다. 예를 들어 다각형을 더 많이 보이게하려면 정보 창을 세로로 66 또는 75 %로 배치하는 것이 좋습니다. (또는 그렇지 않을 수도 있습니다! 그러나 조정할 손잡이가 있습니다.)


0

사용자가 선택한 포인트를 선택한 경우 사용자가 클릭 한 포인트를 사용하여 선택하는 것은 어떻습니까.


마우스 클릭이나 비 공간 쿼리로 선택할 수 있으므로 항상 작동하지는 않습니다.
Jason

0

이 문제도 해결하려고합니다. 폴리곤에 설명 할 내용으로 들어가는 교차 선을 가질 수 없다는 조건을 부과했습니다.

그래서 내 접근 방식은 삼각 측량을 사용합니다. 임의의 정점을 취하십시오 (극단의 N, E, W 또는 S에서 정점을 취하면 상황이 단순화 될 수 있습니다).

이 꼭짓점에서 한 꼭짓점에서 정점까지 선을 그립니다. 즉 꼭짓점이 정점 3 인 경우 꼭짓점 3 + 2를보십시오.

원래 정점에서이 정점까지 선을 만듭니다. 구성된 라인 인 경우 :

  1. 다른 선을 넘지 않고
  2. 중간 점이 다각형 외부에 있지 않습니다

그런 다음 다각형 내에있는 삼각형을 구성했습니다. 성공적인 정점이 n + 2 인 경우 삼각형은 {n, n + 1, n + 2}이며 {v, v1, v2}라고합니다. 그렇지 않으면 다음 정점을 시도하고 모든 정점이 시도 될 때까지 계속하십시오.

삼각형을 찾으면 정점 v에서 v1과 v2의 중간 점까지 선을 가져와 그 중심을 찾으십시오. 해당 선의 중간 점이 삼각형 내부와 다각형 내부에 있어야합니다.

아직이 코드를 작성하지는 않았지만 교차 선이있는 다각형은 실제로 이것이 작동하지 않는 이국적인 조건을 유발할 것이라고 생각합니다. 이것이 다각형 유형이라면 다각형의 각 선분을 테스트하여 교차하지 않는지 확인해야합니다. 교차 된 선분을 건너 뛰면 효과가 있다고 생각합니다.


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