QGIS에서 인접 타일 ID를 확인하는 방법은 무엇입니까?


11

최근 교육 과정에서 QGIS가 아틀라스 생성기를 사용하여 생성 한 맵북의 다음 / 이전 및 위 / 아래 페이지 번호를 자동으로 계산할 수 있는지 물었습니다. 그리드의 너비와 높이를 알고 있다면 일반 그리드에 대해 상당히 합리적인 레이블 표현을 만들었습니다.

그러나 우리는 내 고향 카운티와 같이 관심있는 지역이 포함되지 않은 페이지를 그리고 싶지 않은 현실적인 예를 생각하기 시작했습니다.

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

그래서 오늘 오후에는 파이썬 스크립트에서 각 그리드 셀에 관심이있는 4 명의 이웃을 해결하고 그 값을 그리드에 추가했습니다 (이것은 Ujaval Gandhi의 튜토리얼을 기반으로합니다 ).

for f in feature_dict.values():
    print 'Working on %s' % f[_NAME_FIELD]
    geom = f.geometry()
    # Find all features that intersect the bounding box of the current feature.
    # We use spatial index to find the features intersecting the bounding box
    # of the current feature. This will narrow down the features that we need
    # to check neighboring features.
    intersecting_ids = index.intersects(geom.boundingBox())
    # Initalize neighbors list and sum
    neighbors = []
    neighbors_sum = 0
    for intersecting_id in intersecting_ids:
        # Look up the feature from the dictionary
        intersecting_f = feature_dict[intersecting_id]
        int_geom = intersecting_f.geometry()
        centroid = geom.centroid()
        height = geom.boundingBox().height()
        width = geom.boundingBox().width()
        # For our purpose we consider a feature as 'neighbor' if it touches or
        # intersects a feature. We use the 'disjoint' predicate to satisfy
        # these conditions. So if a feature is not disjoint, it is a neighbor.
        if (f != intersecting_f and
            not int_geom.disjoint(geom)):
            above_point = QgsGeometry.fromPoint(QgsPoint(centroid.asPoint().x(),
               centroid.asPoint().y()+height))
            below_point = QgsGeometry.fromPoint(QgsPoint(centroid.asPoint().x(),
               centroid.asPoint().y()-height))
            left_point = QgsGeometry.fromPoint(QgsPoint(centroid.asPoint().x()-width,
               centroid.asPoint().y()))
            right_point = QgsGeometry.fromPoint(QgsPoint(centroid.asPoint().x()+width,
               centroid.asPoint().y()))
            above = int_geom.contains(above_point)   
            below = int_geom.contains(below_point)   
            left = int_geom.contains(left_point)
            right = int_geom.contains(right_point)
            if above:
                print "setting %d as above %d"%(intersecting_f['id'],f['id'])
                f['above']=intersecting_f['id']

            if below:
                print "setting %d as below %d"%(intersecting_f['id'],f['id'])
                f['below']=intersecting_f['id']

            if left:
                print "setting %d as left of %d"%(intersecting_f['id'],f['id'])
                f['left']=intersecting_f['id']

            if right:
                print "setting %d as right of %d"%(intersecting_f['id'],f['id'])
                f['right']=intersecting_f['id']

    # Update the layer with new attribute values.
    layer.updateFeature(f)

layer.commitChanges()

이것은 잘 작동합니다.

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

그러나 솔직히 말해서 북한에 대한 테스트 지점을 만든 다음 가능한 모든 이웃을 테스트하는 것은 잘못된 것 같습니다. 그러나 오후 내 뇌를 깨고 난 후에 특정 그리드 셀의 북쪽 이웃이 무엇인지 결정하는 더 좋은 방법을 생각할 수 없습니까?

이상적으로는 인쇄 작곡가 텍스트 상자에 넣을만큼 간단한 것을 원하지만 너무 많이 요구하는 것 같습니다.


한쪽에 이웃이 없으면 어떻게 될까요? 클로 셋 셀의 값을 한 방향으로 원하십니까, 아니면 공백을 남기시겠습니까?
radouxju

이 경우 null에 만족합니다. null 또는 비어 있지 않은 경우에만 레이블을 표시하도록 쉽게 설정할 수 있습니다.
Ian Turton

답변:


3

인덱스 레이어에서 각 페이지 범위를 정확하게 작곡가에게 맞추지 않고 두 번째 스크린 샷과 같이 인접한 페이지와 겹치는 테두리가있는 경우 인덱스 레이어의 레이블을 사용할 수 있습니다. 지도 경계 안에 있습니다.

겹치지 않으면 MapInfo에서 과거에 성공적으로 사용했던 기술을 복제 할 수 있습니다 (E & W Sussex!). 각 인덱스 기능에 대해 4 점 세트를 생성하는 작은 스크립트를 작성했습니다. 시트 번호 및 오프셋 방향 속성을 사용하여 인접한 피처로 오프셋합니다. 그런 다음 포인트 레이어를 사용하여 레이블을 다시 생성하고 오프셋 방향으로 레이블의 방향을 조정하여 더 나은 효과를 얻을 수 있습니다.

나는 이것을 시도하지는 않았지만 새로운 지오메트리 생성기 스타일링 기능을 사용하여 QGIS에서 별도의 데이터 레이어를 생성하지 않아도 될 수 있습니다. MapInfo에서 달성 할 수 없었던보다 우아하고 역동적 인 솔루션이 될 것입니다!


다른 다각형의 레이블을 사용하는 것을 정말로 생각해야했습니다! :-) Geometry Generator로 빠른 실험을 한 후 경계 상자를 그릴 수는 있지만 그리드를 만드는 것이 더 어렵습니다
Ian Turton

그리드가 아닌 인접한 다각형으로 오프셋 된 레이블 포인트를 생성하는 선을 따라 생각하고있었습니다. 다른 옵션은 인덱스 피처의 MBR을 인접한 피처로 확장하여 레이블을 그릴 수 있도록하는 것입니다.
Andy Harfoot

방금 게임을했는데 지오메트리 생성기 스타일링으로 생성 된 지오메트리에 레이블이 지정되지 않았으므로 내가 기대했던보다 우아한 솔루션이 아닙니다.
Andy Harfoot

8

실제로 아틀라스를 사용하여 인쇄하려는 타일을 결정하는 데 필요한 대부분의 작업을 이미 수행했습니다. 그러나 요점은 필요한 타일 ID 만 표시하기 위해 모든 것을 함께 조정하는 방법입니다. 내 아이디어를 보여주기 위해이 예제에서는 아래에서 볼 수 있듯이 DEM 이미지와 그리드 벡터 파일을 사용합니다.

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

먼저 각 그리드의 레이블을 표시해야합니다.

레이아웃 뷰에서 그리드를 아틀라스의 커버리지 레이어로 사용했고, 아래에서 볼 수 있듯이 두 개의 맵, 즉 메인 뷰 윈도우 맵과 그리드 만 표시하는 인덱스 맵을 만들었습니다.

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

그런 다음 다음을 수행했습니다.

  1. 전체 그리드 범위를 표시하도록 인덱스 맵의 스케일을 조정 한 다음 스케일을 수정했습니다.
  2. I는 사용시 패닝에서지도를 방지하기 위해 볼 정도 고정 Preview atlas하고,
  3. 나는 활성화 Overview아래 볼 수 있듯이, 기본보기지도의 범위와 위치를 볼 수 :

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

메인 뷰 윈도우 맵의 경우 아래에서 볼 수 있듯이 스케일이 각 그리드 블록의 범위로 고정되어 어떤 일이 발생해도 스케일이 변경되지 않도록합니다.

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

인덱스 맵을 사용하면 기본 뷰 맵 창에서 그리드를 끄더라도 다른 타일을 참조하여 각 타일의 ID와 위치를 쉽게 볼 수 있습니다. 예를 들어 다음 맵의 타일 ID는 14이며 주변 타일 ID를 볼 수 있습니다.

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

업데이트 :

주변 레이아웃의 ID가 아닌 주변 레이아웃의 페이지 번호 색인을 표시하려는 것을 깨달았 기 때문에 답변을 업데이트 할 것입니다.

프로세스를 쉽게 이해할 수 있도록 인덱스 맵에서 ID 번호를 업데이트하여 아래와 같이 레이아웃 페이지 번호를 표시합니다.

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

내가 0 (Zero)에서 시작한 ID이므로 인덱스 맵에 표시된 첫 번째 그리드의 ID는 3에서 시작합니다. 따라서 Atlas의 ID 번호에서 2를 빼서 페이지 번호를 1에서 시작하도록 변경하고 싶습니다. Page number: ID -2그런 다음 현재 페이지 번호를 표현식의 참조로 사용하여 다음과 같이 현재 페이지, 이전 페이지, 다음 페이지, 위 페이지 및 아래 페이지에 대한 레이블을 작성합니다.

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

  • 현재 페이지의 레이블 텍스트 상자에이 표현식이 있습니다. Current Page Number: [%@atlas_pagename%]

  • 이전 페이지 표현 : [%if((@atlas_pagename = 1), Null, '↑ Page Number: ' || (@atlas_pagename - 1))%]1 이전에 페이지 가 없기 때문에

  • 다음 페이지 표현 : [%if( (@atlas_pagename = 25), Null, '↓ Page Number: ' || (@atlas_pagename + 1))%]25 이후에 페이지가 없기 때문에

  • Up Page expression : [%if((@atlas_pagename <= 6),NULL,'↑ Page Number: ' || (@atlas_pagename -6))%]위쪽 방향으로 6 이전의 페이지가 없기 때문에

  • 아래 페이지 표현 : [%if((@atlas_pagename >= 20), Null, '↓ Page Number: ' || (@atlas_pagename + 6))%]아래쪽으로 20 이후에 페이지가 없기 때문에

일부 출력 결과 :

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

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

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

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


유용하지만 이것은 그의 질문에 대답하지 않습니다.
Victor

@Victor 귀하의 의견에 감사드립니다. 내 답변을 업데이트했습니다.
ahmadhanb

이것은 키 맵 / 그리드의 측면이 규칙적이므로 예제 (및 그의)에서 작동합니다. 그것들이 똑 바르지 않다면 더하거나 빼는 숫자 (예에서 6)가 현재 아틀라스 페이지에 따라 다르기 때문에 작동하지 않습니다.
Victor

2
동의합니다. 그리드가 규칙적이지 않으면 프로세스가 더 복잡해집니다. 그러나 그는 정기적 인 그리드에 적용하려고하므로 제안 된 솔루션에 적용된 방법이 효과적입니다.
ahmadhanb

다른 좋은 아이디어가있을 경우를 대비하여 사실을 주목하십시오! 특히 그리드가 규칙적이지 않기 때문에!
Victor

2

이 솔루션은 직사각형 그리드에 적용되며 자동입니다 (수동으로 조정하지 않고도 모든 시나리오에서 작동해야 함).

페이지 번호가있는 격자가 있다고 가정 해 봅시다. 그리드 레이어와 페이지 번호 필드를 매개 변수로 선택하여 처리 스크립트 를 실행할 수 있습니다 . 스크립트 right, left, above, below는 그리드 레이어에 네 개의 필드 ( )를 만들고 각 그리드 셀에 해당하는 인접 페이지 ID를 계산합니다. 그런 다음 표현식 (예 :)을 사용하여 [% if( "left" is not NULL, 'to page' || "left", "" ) %]인접 페이지 레이블을 표시 할 수 있습니다 .

QGIS Resource Sharing 플러그인에서 내 저장소 ( https://github.com/gacarrillor/QGIS-Resources.git )를 추가 하고 스크립트를 설치하십시오. 여기에 이미지 설명을 입력하십시오

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

작동 원리

스크립트는 현재 그리드 셀과 각 교차 셀의 경계 상자 좌표를 비교하여 관계 (오른쪽, 왼쪽, 위 또는 아래)를 결정합니다. 각 관계에 대해 좌표 중 하나가 누락되었습니다.

관계가 인 above경우, 누락 된 좌표는 yMin즉, 현재 그리드 셀의 경계 상자에서 다른 모든 3 개의 좌표가 위의 셀 경계 상자에 나타납니다. QGIS 경계 상자는 다음 순서로 정의됩니다 [xMin, yMin, xMax, yMax].

숫자 예제의 경우 길이가 1 인 직사각형을 예로 들어 보겠습니다. 현재 셀의 경계 상자가로 정의되어 있다고 가정 bbox1=[0,0,1,1]합니다. 위의 셀 경계 상자는로 정의됩니다 bbox2=[0,1,1,2]. bbox1의 X 좌표는 bbox2에 있고 bbox1은 bbox2의 yMinY 좌표에 없습니다.

이 방법으로 4 가지 관계를 정의 할 수 있습니다 (o : present, # : missing) :

right: [#,o,o,o]
above: [o,#,o,o]
left:  [o,o,#,o]
below: [o,o,o,#]

보시다시피 누락 된 인덱스는 필요한 모든 정보를 제공합니다.

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