Come determinare gli ID di tile vicini in QGIS?


11

In un recente corso di formazione mi è stato chiesto se QGIS potesse calcolare automaticamente i numeri di pagina successiva / precedente e sopra / sotto per un libro di mappe creato usando il generatore di atlanti. Sono riuscito a elaborare un'espressione dell'etichetta abbastanza ragionevole per una griglia normale se conosci la larghezza e l'altezza della griglia.

Ma poi abbiamo iniziato a pensare ad esempi realistici in cui non vogliamo disegnare pagine che non contengono il nostro distretto di interesse, come questo del mio paese di origine:

inserisci qui la descrizione dell'immagine

Quindi oggi pomeriggio ho suonato in uno script Python per elaborare i 4 vicini a cui ero interessato per ogni cella della griglia e ho aggiunto quei valori alla mia griglia (questo è fortemente basato sul tutorial di 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()

Questo funziona bene.

inserisci qui la descrizione dell'immagine

Ma ad essere sincero, il tutto creando un punto di prova a nord e poi testando tutti i possibili vicini sembra sbagliato. Tuttavia, dopo un pomeriggio di distruzione del mio cervello, non riesco a pensare a un modo migliore per determinare quale sia il vicino settentrionale di una particolare cellula della griglia?

Idealmente, vorrei qualcosa di abbastanza semplice da inserire in una casella di testo per il compositore di stampe, ma sospetto che sia troppo da chiedere.


E se non ci fosse un vicino di casa da una parte. Vuoi il valore della cella closeset in una direzione o lasceresti un vuoto?
Radouxju,

Sono contento per un null in quel caso, posso facilmente impostare l'etichetta per visualizzare solo quando non è nullo o vuoto.
Ian Turton

Risposte:


3

Se non stai adattando ogni estensione di pagina (dal livello dell'indice) esattamente nel compositore, ma invece hai bordi sovrapposti con pagine adiacenti (come mostrato nel tuo secondo screenshot), allora potresti usare le etichette dal livello dell'indice, con il lato negativo che sarebbero all'interno del bordo della mappa.

Se non ci sono sovrapposizioni, potresti replicare una tecnica che ho usato con successo in passato (per coincidenza con E & W Sussex!) In MapInfo, dove ho scritto un piccolo script che ha generato un set di quattro punti per ogni caratteristica dell'indice , offset nelle feature adiacenti, con attributi sia del numero del foglio, sia della direzione dell'offset. Lo strato di punti è stato quindi utilizzato per generare nuovamente le etichette, con la direzione dell'offset che consente di regolare l'orientamento delle etichette per un effetto più gradevole.

Non ho provato questo, ma potresti essere in grado di evitare di generare un livello dati separato in QGIS attraverso l'uso della nuova funzionalità di stile del generatore di geometria, questo renderebbe una soluzione più elegante e dinamica che non era possibile ottenere in MapInfo!


Avrei davvero pensato di usare solo le etichette degli altri poligoni! :-) Dopo un rapido esperimento con Geometry Generator posso disegnare un riquadro di delimitazione, ma è più difficile costruire una griglia
Ian Turton

Stavo pensando di generare punti etichetta spostati nei poligoni adiacenti, piuttosto che griglie. Un'altra opzione sarebbe quella di espandere l'MBR della funzione di indice nelle funzioni adiacenti per consentire di disegnare le etichette.
Andy Harfoot,

Ho appena fatto un gioco e sembra che la geometria generata dallo stile del generatore di geometria non sia etichettata, quindi non è la soluzione più elegante che avevo sperato.
Andy Harfoot,

8

In realtà, hai già svolto la maggior parte del lavoro richiesto per determinare le piastrelle che desideri stampare usando l'atlante. Ma il punto è come regolare tutto insieme per mostrare solo gli ID delle tessere di cui hai bisogno. Per dimostrare la mia idea, userò in questo esempio un'immagine DEM e un file vettoriale griglia, come puoi vedere di seguito:

inserisci qui la descrizione dell'immagine

Per prima cosa dobbiamo mostrare l'etichetta di ogni griglia.

Nella vista layout, ho usato la griglia come livello di copertura nell'atlante, ho creato due mappe: la mappa della finestra della vista principale e una mappa dell'indice che mostra solo la griglia, come puoi vedere di seguito:

inserisci qui la descrizione dell'immagine

Quindi ho fatto quanto segue:

  1. Ho regolato la scala della mappa dell'indice per mostrare l'intera estensione della griglia, quindi ho corretto la scala
  2. Ho corretto l'estensione della vista per impedire la panoramica della mappa durante l'utilizzo Preview atlase
  3. Ho abilitato Overviewa vedere l'estensione e la posizione della mappa della vista principale, come puoi vedere di seguito:

inserisci qui la descrizione dell'immagine

Per la mappa della finestra della vista principale, ho fissato la scala all'estensione di ciascun blocco della griglia, per essere sicuro che la scala non verrà modificata se dovesse succedere qualcosa, come puoi vedere di seguito;

inserisci qui la descrizione dell'immagine

Utilizzando una mappa indice, è possibile visualizzare facilmente l'ID e la posizione di ogni riquadro con riferimento ad altri riquadri, anche quando si spegne la griglia dalla finestra della mappa della vista principale. Ad esempio, la seguente mappa ha un ID tessera = 14 e puoi vedere gli ID tessere circostanti.

inserisci qui la descrizione dell'immagine

Aggiornamento :

Aggiornerò la mia risposta perché mi sono reso conto che volevi mostrare l'indice del numero di pagina dei layout circostanti e non gli ID dei layout circostanti.

Per facilitare la comprensione del processo, aggiornerò i numeri ID nella mappa dell'indice per mostrare il numero di pagina del layout, come mostrato di seguito:

inserisci qui la descrizione dell'immagine

Poiché gli ID che ho iniziato da 0 (Zero), l'ID della prima griglia mostrata sulla mappa dell'indice inizierà da 3. Pertanto, voglio cambiare il numero di pagina per iniziare da 1 sottraendo 2 dal numero ID in Atlas: Page number: ID -2, quindi userò il numero di pagina corrente come riferimento nell'espressione per creare etichette per la pagina corrente, la pagina precedente, la pagina successiva, la pagina in alto e la pagina in basso, come segue:

inserisci qui la descrizione dell'immagine

  • Pagina corrente ha questa espressione nella casella di testo dell'etichetta: Current Page Number: [%@atlas_pagename%]

  • Espressione di pagina precedente: [%if((@atlas_pagename = 1), Null, '↑ Page Number: ' || (@atlas_pagename - 1))%]poiché non ci sono pagine prima di 1

  • Espressione Pagina successiva: [%if( (@atlas_pagename = 25), Null, '↓ Page Number: ' || (@atlas_pagename + 1))%]poiché non ci sono pagine dopo 25

  • Up Espressione di pagina: [%if((@atlas_pagename <= 6),NULL,'↑ Page Number: ' || (@atlas_pagename -6))%]poiché non ci sono pagine prima di 6 nella direzione superiore

  • Espressione Pagina sotto: [%if((@atlas_pagename >= 20), Null, '↓ Page Number: ' || (@atlas_pagename + 6))%]poiché non ci sono pagine dopo 20 nella direzione inferiore

Alcuni risultati di output:

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


Sebbene utile, questo non risponde alla sua domanda.
Victor,

@Victor Grazie per il tuo commento, ho aggiornato la mia risposta.
ahmadhanb,

questo funziona nel tuo esempio (e nel suo), poiché i lati della mappa / griglia dei tasti sono regolari. Se non fossero diritti, non funzionerebbe poiché il numero da aggiungere o sottrarre (6 nel tuo esempio) varierebbe a seconda della pagina dell'atlante in cui ti trovi.
Victor,

2
Sono d'accordo con te. Se la griglia non è regolare, il processo sarà più complicato. Ma dal momento che vuole applicarlo su una griglia regolare, il metodo applicato nella mia soluzione suggerita funzionerà.
ahmadhanb,

notando il fatto, nel caso abbiate un'altra buona idea! Soprattutto perché la mia griglia non è regolare!
Victor,

2

Questa soluzione funzionerà per le griglie rettangolari ed è automatica (dovrebbe funzionare per qualsiasi scenario senza regolare nulla manualmente).

Supponiamo che tu abbia una griglia con i numeri di pagina. Puoi eseguire il mio script di elaborazione selezionando il livello della griglia e il relativo campo del numero di pagina come parametri. Lo script crea quattro campi ( right, left, above, below) nel livello della griglia e calcola l'id della pagina adiacente corrispondente per ogni cella della griglia. Quindi puoi usare le tue espressioni (ad es. [% if( "left" is not NULL, 'to page' || "left", "" ) %]) Per mostrare le etichette delle pagine vicine.

Basta aggiungere il mio repository ( https://github.com/gacarrillor/QGIS-Resources.git ) dal plugin QGIS Resource Sharing e installare lo script: inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

Come funziona

Lo script determina la relazione (destra, sinistra, sopra o sotto) confrontando le coordinate dei riquadri di delimitazione sia dalla cella della griglia corrente che da ciascuna cella che si intersecano. Si scopre che per ogni relazione manca una delle coordinate.

Se la relazione è above, la coordinata mancante è yMin, cioè, tutte le altre 3 coordinate dal riquadro di selezione della cella della griglia corrente saranno presenti nel riquadro di selezione della cella sopra. Ricordate che QGIS scatole di delimitazione sono definiti in questo ordine: [xMin, yMin, xMax, yMax].

Per un esempio numerico prendiamo rettangoli con lati di lunghezza 1. Supponiamo che il riquadro di delimitazione della cella corrente sia definito come bbox1=[0,0,1,1]. Il riquadro di selezione della cella sopra sarebbe definito come bbox2=[0,1,1,2]. Le coordinate X da bbox1 sono presenti in bbox2, mentre quelle di bbox1 yMinmancano nelle coordinate Y di bbox2.

Possiamo definire le nostre 4 relazioni in questo modo (o: presente, #: mancante):

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

Come puoi vedere, l'indice mancante ci fornisce tutte le informazioni di cui abbiamo bisogno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.