Bagaimana cara menentukan id ubin tetangga di QGIS?

11

Saya ditanya dalam kursus pelatihan baru-baru ini jika QGIS dapat secara otomatis menghitung nomor halaman berikutnya / sebelumnya dan di atas / di bawah untuk buku peta yang dibuat menggunakan generator atlas. Saya berhasil membuat ekspresi label yang cukup masuk akal untuk kisi biasa jika Anda tahu lebar dan tinggi kisi.

Tetapi kami kemudian mulai memikirkan contoh-contoh realistis di mana kami tidak ingin menggambar halaman yang tidak mengandung distrik minat kami, seperti ini salah satu daerah asal saya:

masukkan deskripsi gambar di sini

Jadi sore ini saya bermain di skrip python untuk mengetahui 4 tetangga yang saya tertarik untuk setiap sel grid dan menambahkan nilai-nilai itu ke kotak saya (ini sangat didasarkan pada tutorial 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()

Ini berfungsi dengan baik.

masukkan deskripsi gambar di sini

Tapi jujur ​​saja, keseluruhan menciptakan titik uji ke Utara dan kemudian menguji semua tetangga yang mungkin tampak salah. Namun setelah satu sore mengacaukan otak saya, saya tidak bisa memikirkan cara yang lebih baik untuk menentukan apa tetangga utara sel grid tertentu?

Idealnya saya ingin sesuatu yang cukup sederhana untuk dimasukkan ke dalam kotak teks komposer cetak, tapi saya kira itu terlalu banyak untuk diminta.

Ian Turton
sumber
bagaimana jika tidak ada tetangga di satu sisi. Apakah Anda ingin nilai sel closeset dalam satu arah atau Anda akan meninggalkan kekosongan?
radouxju
Saya senang untuk null dalam hal ini, saya dapat dengan mudah mengatur label untuk hanya menampilkan ketika tidak nol atau kosong.
Ian Turton

Jawaban:

3

Jika Anda tidak menyesuaikan setiap batas halaman (dari lapisan indeks) tepat ke komposer, tetapi memiliki batas yang tumpang tindih dengan halaman yang berdekatan (seperti yang ditunjukkan pada tangkapan layar kedua), maka Anda dapat menggunakan label dari lapisan indeks, dengan kelemahan yang mereka akan berada di dalam perbatasan peta.

Jika tidak ada tumpang tindih, maka Anda dapat meniru teknik yang saya gunakan dengan sukses di masa lalu (kebetulan di E & W Sussex!) Di MapInfo, di mana saya menulis skrip kecil yang menghasilkan serangkaian empat poin untuk setiap fitur indeks , diimbangi ke fitur yang berdekatan, dengan atribut dari kedua nomor sheet, dan arah offset. Lapisan titik kemudian digunakan untuk menghasilkan label lagi, dengan arah ofset memungkinkan orientasi label disesuaikan untuk efek yang lebih baik.

Saya belum mencoba ini, tetapi Anda mungkin dapat menghindari pembuatan lapisan data terpisah di QGIS melalui penggunaan fungsi penataan generator geometri baru, ini akan membuat solusi yang lebih elegan dan dinamis yang tidak dapat dicapai di MapInfo!

Andy Harfoot
sumber
Saya benar-benar harus memikirkan hanya menggunakan label poligon lain! :-) Setelah percobaan cepat dengan Geometry Generator saya dapat menggambar kotak pembatas, tetapi lebih sulit untuk membangun kotak
Ian Turton
Saya berpikir sepanjang garis menghasilkan titik label mengimbangi ke dalam poligon yang berdekatan, daripada grid. Pilihan lain adalah untuk memperluas MBR fitur indeks ke fitur yang berdekatan untuk memungkinkan label untuk ditarik.
Andy Harfoot
Baru saja bermain, dan tampaknya geometri yang dihasilkan oleh gaya generator geometri tidak diberi label, jadi bukan solusi yang lebih elegan yang saya harapkan.
Andy Harfoot
8

Sebenarnya, Anda sudah melakukan sebagian besar pekerjaan yang diperlukan untuk menentukan ubin yang ingin Anda cetak menggunakan atlas. Tetapi intinya adalah bagaimana menyesuaikan semuanya untuk hanya menampilkan ID ubin yang Anda butuhkan. Untuk menunjukkan ide saya, saya akan menggunakan dalam contoh ini gambar DEM dan file vektor kotak, seperti yang Anda lihat di bawah:

masukkan deskripsi gambar di sini

Pertama-tama kita perlu menunjukkan label setiap kotak.

Dalam tampilan tata letak, saya menggunakan kisi sebagai lapisan cakupan di atlas, saya membuat dua peta: peta jendela tampilan utama, dan peta indeks yang hanya menampilkan kisi, seperti yang Anda lihat di bawah:

masukkan deskripsi gambar di sini

Kemudian saya melakukan yang berikut:

  1. Saya menyesuaikan skala peta indeks untuk menunjukkan seluruh luas grid kemudian saya memperbaiki skala
  2. Saya memperbaiki jangkauan tampilan untuk mencegah panning peta saat menggunakan Preview atlas, dan
  3. Saya mengaktifkannya Overviewuntuk melihat jangkauan dan lokasi peta tampilan utama, seperti yang Anda lihat di bawah:

masukkan deskripsi gambar di sini

Untuk peta jendela tampilan utama, saya memperbaiki skala sejauh setiap blok kotak, untuk memastikan bahwa skala tidak akan berubah jika terjadi sesuatu, seperti yang Anda lihat di bawah;

masukkan deskripsi gambar di sini

Menggunakan peta indeks, Anda dapat dengan mudah melihat ID dan lokasi setiap ubin dengan merujuk ke ubin lain, bahkan ketika Anda mematikan grid dari jendela peta tampilan utama. Misalnya, peta berikut memiliki ID ubin = 14, dan Anda dapat melihat ID ubin di sekitarnya.

masukkan deskripsi gambar di sini

Perbarui :

Saya akan memperbarui jawaban saya karena saya menyadari bahwa Anda ingin menampilkan indeks nomor halaman dari tata letak di sekitarnya, bukan ID dari tata letak di sekitarnya.

Untuk memudahkan pemahaman proses, saya akan memperbarui nomor ID di peta indeks untuk menampilkan nomor halaman tata letak, seperti yang ditunjukkan di bawah ini:

masukkan deskripsi gambar di sini

Karena ID yang saya mulai dari 0 (Nol), ID dari grid pertama yang ditunjukkan pada peta indeks akan mulai dari 3. Oleh karena itu, saya ingin mengubah nomor halaman untuk memulai dari 1 dengan mengurangi 2 dari nomor ID di Atlas: Page number: ID -2, maka saya akan menggunakan nomor halaman saat ini sebagai referensi dalam ekspresi untuk membuat label untuk halaman saat ini, halaman sebelumnya, halaman berikutnya, halaman atas dan halaman di bawah, sebagai berikut:

masukkan deskripsi gambar di sini

  • Halaman Saat Ini memiliki ungkapan ini di kotak teks label: Current Page Number: [%@atlas_pagename%]

  • Ekspresi Halaman Sebelumnya: [%if((@atlas_pagename = 1), Null, '↑ Page Number: ' || (@atlas_pagename - 1))%]karena tidak ada halaman sebelum 1

  • Ekspresi Halaman Berikutnya: [%if( (@atlas_pagename = 25), Null, '↓ Page Number: ' || (@atlas_pagename + 1))%]karena tidak ada halaman setelah 25

  • Ekspresi Halaman Atas: [%if((@atlas_pagename <= 6),NULL,'↑ Page Number: ' || (@atlas_pagename -6))%]karena tidak ada halaman sebelum 6 di arah atas

  • Di bawah ekspresi Halaman: [%if((@atlas_pagename >= 20), Null, '↓ Page Number: ' || (@atlas_pagename + 6))%]karena tidak ada halaman setelah 20 di arah bawah

Beberapa hasil keluaran:

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

ahmadhanb
sumber
Meskipun bermanfaat, ini tidak menjawab pertanyaannya.
Victor
@ Viktor Terima kasih atas komentar Anda, saya memperbarui jawaban saya.
ahmadhanb
ini berfungsi pada contoh Anda (dan miliknya), karena sisi-sisi keymap / grid teratur. Jika tidak lurus, itu tidak akan berfungsi karena angka yang ditambahkan atau dikurangi (6 dalam contoh Anda) akan bervariasi tergantung pada halaman atlas tempat Anda berada.
Victor
2
Saya setuju dengan kamu. Jika grid tidak teratur prosesnya akan lebih rumit. Tetapi karena dia ingin menerapkannya pada grid biasa, metode yang diterapkan dalam solusi yang saya sarankan akan berfungsi.
ahmadhanb
hanya mencatat fakta, jika Anda punya ide bagus! Terutama karena kisi saya tidak teratur!
Victor
2

Solusi ini akan bekerja untuk kisi-kisi persegi panjang dan otomatis (harus bekerja untuk skenario apa pun tanpa menyesuaikan apa pun secara manual).

Anggap Anda memiliki kisi dengan nomor halaman. Anda dapat menjalankan skrip Pemrosesan saya dengan memilih layer grid dan bidang nomor halamannya sebagai parameter. Script membuat empat bidang ( right, left, above, below) di layer grid dan menghitung id halaman tetangga yang sesuai untuk setiap sel grid. Kemudian Anda dapat menggunakan ekspresi Anda (misalnya, [% if( "left" is not NULL, 'to page' || "left", "" ) %]) untuk menampilkan label halaman tetangga.

Cukup tambahkan repositori saya ( https://github.com/gacarrillor/QGIS-Resources.git ) dari plugin QGIS Resource Sharing dan instal skrip: masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Bagaimana itu bekerja

Script menentukan hubungan (kanan, kiri, atas, atau di bawah) dengan membandingkan koordinat kotak pembatas dari sel kisi saat ini dan setiap sel yang berpotongan. Ternyata untuk setiap relasi, salah satu koordinat tidak ada.

Jika hubungannya adalah above, koordinat yang hilang adalah yMin, yaitu, semua 3 koordinat lainnya dari kotak pembatas sel grid saat ini akan hadir dalam kotak pembatas sel di atas. Ingat bahwa QGIS kotak bounding didefinisikan dalam urutan ini: [xMin, yMin, xMax, yMax].

Sebagai contoh numerik, mari kita ambil persegi panjang dengan sisi panjang 1. Katakanlah kotak pembatas sel saat ini didefinisikan sebagai bbox1=[0,0,1,1]. Kotak pembatas sel di atas akan didefinisikan sebagai bbox2=[0,1,1,2]. Koordinat X dari bbox1 ada di bbox2, sedangkan bbox1 yMinhilang dalam koordinat Y dari bbox2.

Kita dapat mendefinisikan 4 relasi kita dengan cara ini (o: sekarang, #: hilang):

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

Seperti yang Anda lihat, indeks yang hilang memberi kami semua informasi yang kami butuhkan.

Germán Carrillo
sumber