Nella mailing list del gruppo utenti italiani QGIS è apparso un quesito molto interessante, ecco un un estratto:
…[Ho generato un Atlante di 130 pagine in formato A3 di un territorio molto vasto e nel quale è riportato un layer di punti (all’incirca 350 punti) disseminati variamente su tutto questo territorio.Per il 99% va tutto bene. In alcune tavole dell’Atlante però, capita che alcuni punti vadano a cadere proprio in adiacenza del bordo della tavola (alias, in adiacenza del bordo del rettangolo del layer di copertura dell’Atlante).
Ora, il punto, ovviamente, a stampa si vede e viene stampato ma l’etichetta associata a questi punti (si tratta, in tutto di 4 punti su oltre 350), poichè è spostata di qualche millimetro rispetto al punto, non si vede perchè va fuori campo di stampa, cioè capita fuori l’area del rettangolo del layer di copertura dell’Atlante che in quel momento sta andando a stampa.
Esiste un comando “forzatura” per imporre al compositore di stampe di far sempre, comunque e in ogni caso far ricadere entro la tavola tutte le etichette associate ai punti ricadenti nella tavola?] …
Ho prospettato due soluzioni: una molto rapida, ma in certe condizioni potrebbe non essere utilizzata per problemi legati alla scala di rappresentazione; una seconda molto più complessa ma che risolve del tutto il problema nel caso di vettore di copertura rettangolare (nel caso generico NON ho avuto il tempo di testarlo!!!).
Non avendo i dati a disposizione, uso dei dati fittizi ma utili allo scopo:
- vettore di punti (pti_pill);
- vettore reticolo poligonale che ricopre i punti (reticolo);

Vediamo un dettaglio del problema:

Come si vede alcune etichette NON sono visibili o tranciate!.
Prima soluzione:
La prima soluzione si basa su una semplice tematizzazione dei punti tramite una regola; tale regola fa si che si vedano solo i punti ricadenti nel vettore di copertura corrente:

assieme alla regola occorre attivare ‘il margine attorno all’elemento‘ :

questa soluzione va bene se non si hanno restrizioni sulla scala di rappresentazione.
Seconda soluzione:
In questo caso creeremo una espressione che legga la posizione del punto rispetto al rettangolo e se troppo vicino ai bordi (definito tramite una variabile @dist_bordo) deve cambiare il quadrante (TLS,BSR ecc..) di posizionamento dell’etichetta; i casi possibili sono 4: sopra, sotto, destra o sinistra.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CASE | |
WHEN | |
length( shortest_line( $geometry, boundary( @atlas_geometry ) ) ) < @dist_bordo | |
and | |
angle_at_vertex( shortest_line( $geometry, boundary( @atlas_geometry ) ) ,0) =180 | |
THEN 'TSL' | |
WHEN | |
length( shortest_line( $geometry, boundary( @atlas_geometry ))) <@dist_bordo | |
and | |
angle_at_vertex( shortest_line( $geometry, boundary( @atlas_geometry ) ),0 ) =0 | |
THEN 'BSR' | |
WHEN | |
length( shortest_line( $geometry, boundary( @atlas_geometry) ) ) <@dist_bordo | |
and | |
angle_at_vertex( shortest_line( $geometry, boundary( @atlas_geometry ) ),0 ) =270 | |
THEN 'R' | |
WHEN | |
length( shortest_line( $geometry, boundary( @atlas_geometry )) ) <@dist_bordo | |
and | |
angle_at_vertex( shortest_line( $geometry, boundary( @atlas_geometry ) ),0 )=90 | |
THEN 'L' | |
END |
questa espressione, da usare nelle etichette, è stata definita per metodo cartographic- position priority:

dove gli ingressi attesi sono:

magicamente:

FATTO!!!
APPROFONDIMENTO
approfondiamo la logica della riga 3 e 5, le altre sono una ripetizione.
riga 3: length( shortest_line( $geometry, boundary( @atlas_geometry ) ) )<@dist_bordo
- @atlas_geometry : è la geometria corrente dell’atlas;
- boundary( @atlas_geometry ): ricava il limite topologico della geometria corrente dell’atlas (da poligono a linea);
- shortest_line( $geometry, boundary( @atlas_geometry ) ) ): disegna la linea (segmento) più breve tra la $geometry (relativa la punto) e il bordo della geometria corrente dell’atlas;
- length( shortest_line( $geometry, boundary( @atlas_geometry ) ) ): calcola la lunghezza del segmento;
quindi la riga 3, espressa in parole umane: calcola la lunghezza minima tra il punto e il bordo del rettangolo che lo contiene.
riga 5: angle_at_vertex( shortest_line($geometry, boundary( @atlas_geometry ) ) ,0) =180
- shortest_line($geometry, boundary( @atlas_geometry ) ): come sopra;
- angle_at_vertex(geometry, vertex): richiede una geometria (quella di sopra, cioè il segmento minimo) e un vertice di quest’ultimo che può essere 1 o 0;
quindi la riga 5, espressa graficamente:

l’intera espressione analizza i quattro casi (0,90,180 o 270°):
- 0: il punto si trova sotto il bordo;
- 90: il punto si trova a sinistra del bordo;
- 180: il punto si trova sopra il bordo;
- 270: il punto si trova a destra del bordo.
NOTE FINALI: non so se è una mia lacuna o meno, ma questa funzionalità dovrebbe essere presente in QGIS; ma intuisco che non è di semplice implementare in quanto dipende fortemente dal vettore di copertura. Ringrazio Marco Spaziani per aver posto il problema in ML QGIS-it-user (iscrivetevi!) e ringrazio G. Allegri per avermi dato lo spunto, altrimenti non avrei mai approfondito il problema.
EDIT:
Nel caso generico, cioè con vettore di copertura NON rettangolare, basti usare questa espressione (grazie al suggerimento di G. Allegri)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CASE | |
WHEN | |
length( shortest_line( $geometry, boundary( bounds( @atlas_geometry ) ) ) ) < @dist_bordo | |
and | |
angle_at_vertex( shortest_line( $geometry, boundary( bounds( @atlas_geometry ) ) ) ,0) =180 | |
THEN 'TSL' | |
WHEN | |
length( shortest_line( $geometry, boundary( bounds( @atlas_geometry ) ))) <@dist_bordo | |
and | |
angle_at_vertex( shortest_line( $geometry, boundary( bounds( @atlas_geometry ) ) ),0 ) =0 | |
THEN 'BSR' | |
WHEN | |
length( shortest_line( $geometry, boundary( bounds( @atlas_geometry) ) ) ) <@dist_bordo | |
and | |
angle_at_vertex( shortest_line( $geometry, boundary( bounds( @atlas_geometry ) ) ),0 ) =270 | |
THEN 'R' | |
WHEN | |
length( shortest_line( $geometry, boundary( bounds( @atlas_geometry ) )) ) <@dist_bordo | |
and | |
angle_at_vertex( shortest_line( $geometry, boundary( bounds( @atlas_geometry ) ) ),0 )=90 | |
THEN 'L' | |
END |
NB:
- la funzione angle_at_vertex() e boundary () sono stata introdotta nella 2.18;
- la funzione shortest_line () è stata introdotta nella 2.14.
Buon lavoro.
ConQGIStando
donate al progetto QGIS:
se il l’articolo vi è stato utile:
https://www.paypal.me/pigrecoinfinito
Salvatore, non capisco cosa siano le uscite del CASE WHEN THAN. Mi riferisco a ‘TSL’ ?
"Mi piace""Mi piace"
Ciao Luca,
ho appena aggiunto il significato dei valori attesi.
ciao
"Mi piace""Mi piace"
Scusami, che sbadato sono stato. Mi ero perso nell0impressionante uso del codice e dele funzioni, che mi ero dimenticato che, tutit i comandi dinamici, hanno dei valori in uscita predeterminati, bastava leggerli nella descrizione del comando…. 😉 che genialata, ora é evidente che si puó far davveri tutto!!
"Mi piace""Mi piace"
Ciao! ho appena rivisto quresto turtorial: dovrebbe funzionare anche se noné un atlas, vero?
"Mi piace"Piace a 1 persona
Ciao Luca,
sì, in generale dovrebbe funzionare.
ciao
"Mi piace""Mi piace"