Come interrompere le linee di contorno sotto le etichette di prospetto (anziché utilizzare i buffer delle etichette)?


32

C'è un modo per interrompere una linea di contorno sotto un'etichetta di elevazione?

inserisci qui la descrizione dell'immagine


ArcGIS? QGIS? Personalizzato?
Ragi Yaser Burhum

1
Uso il qgis per l'etichettatura dei contorni
MAP

Accetteresti una risposta che richiede PostGIS?
Scro

3
sfortunatamente: no :) Ma c'è un modo per risolvere il problema con PostGIS?
MAP

Risposte:


22

Sì, fattibile. Normalmente suggerirei un buffer parzialmente trasparente, ma vedo perché vuoi farlo cartograficamente.

Questo potrebbe essere lento e devi decidere manualmente dove vuoi che vadano le etichette, ma dal punto di vista cartografico, non è una brutta cosa!

Ecco uno screenshot ...

Come puoi vedere, nessun buffer. Il raster sottostante non è interessato. Ho incluso linee di contorno intermedie più sottili e le ho disegnate in modo che vengano visualizzate solo quando ELEV% 50 <> 0

esempio di linee di contorno interrotte

L'ho fatto in QGIS 2.12 ... il tuo chilometraggio può variare con le versioni precedenti.

Suppongo che qui ci sia un campo "ELEV" su ogni linea di contorno.

Segmenta le linee di contorno

  1. Utilizzare l'elaborazione e l'algoritmo GRASS v.split.length per dividere i contorni in segmenti di uguale lunghezza. Devi scegliere una lunghezza che sarà vicina alla dimensione dell'etichetta in unità della mappa, supponendo che tu stia utilizzando i metri. Qui ho usato 200m.

    Fai attenzione perché renderà il tuo file molto, molto più grande (nota che la funzione conta nello screenshot).

    Per ovviare a questo, potresti voler generare solo quelle linee di contorno che desideri modellare (ad esempio ogni 50 o 100 metri) per evitare di elaborare tutte le linee di contorno intermedie.

  2. A questo livello, aggiungi un campo intero di 1 cifra chiamato showLabel . L'impostazione predefinita è 0 o NULL.

  3. Modifica l'etichetta per mostrarla solo su un segmento in cui questo campo è impostato su 1. Utilizzalo per l'espressione del testo dell'etichetta ...

    if ( "showlabel" is not null, "ELEV", "")
    

    Penso che (espressione, valore reale, valore falso) sia abbastanza nuovo; se si utilizza una versione precedente, è possibile utilizzare CASE-ELSE

  4. Cambia lo stile della linea in modo che tutti i segmenti a lunghezza fissa siano disegnati, ad eccezione di quelli in cui viene visualizzata l'etichetta. Quindi usa il rendering basato su regole con due regole

    Rule 1: "showLabel" is null
    Black, 0% transparent
    
    Rule 2: "showLabel" is not null
    Any colour, 100% transparent
    

    Ora, tutti i contorni verranno visualizzati per impostazione predefinita, ma nessuna etichetta.

    Modifica manualmente i segmenti in cui desideri mostrare le etichette

    Passare alla modalità di modifica e selezionare manualmente i segmenti in cui si desidera visualizzare i valori del contorno, quindi impostare il valore su showLabel1 per le funzioni selezionate. Puoi usare Ctrl+ select (su Ubuntu / Win, Cmd+ Ctrl+ Click / su Mac?) Per selezionare più segmenti per velocizzare le cose.

    Questo dovrebbe ora "tagliare" i contorni in cui si desidera mostrare le etichette e le etichette verranno visualizzate negli spazi.

In questo caso, le mie impostazioni dell'etichetta erano:

CRS: EPSG 27700 (Local UTM for UK, in meters)
Text size: 50 map units
Placement: Parallel, On Line

Spero che sia d'aiuto!


5
Questa è l'unica soluzione pienamente funzionante che posso immaginare. Molto doloroso, se ci sono molte etichette, non riesco a immaginare di fare tutte le mappe delle mie teste delle acque sotterranee (migliaia all'anno) in questo modo. Sarebbe bello se in futuro questo fosse realizzabile attraverso lo stile, poiché il migliore sarebbe il modello di linea personalizzato e l'etichetta ripetizione + offset.
Miro,

2
Solo alcune idee per facilitare l'attività: per selezionare più segmenti per disegnare l'etichetta, Seleziona per poligono o Seleziona per mano libera può essere utile. Inoltre, un altro approccio sarebbe la creazione di un livello di linea di graffio per disegnare linee che intercettano i contorni e quindi eseguire un Seleziona per posizione.
Alexandre Neto,

7

Uso l'opzione "Buffer" nella scheda "Impostazione etichetta". (Usando il pulsante etichette, non la vecchia opzione etichette nella finestra di dialogo delle proprietà del livello.) Questo non cancella la linea di contorno, come immagino che tu voglia fare, ma rende leggibile l'etichetta.


4
Non ci avevo mai pensato prima, ma sarebbe conveniente se invece di assegnare un colore per il buffer, potessi scegliere di applicarlo come 'knockout' ai livelli selezionati.
Scro,

5
L'ultima versione di QGIS ha buffer trasparenti in modo da poter ridurre l'impatto su altre parti della mappa.
Nathan W,

1
@MAP Un knockout cancella i pixel sottostanti. Se fosse un'opzione, in questo caso sceglieresti di eliminare il livello del contorno.
Scro,

1
knockout - il termine esri è "mascherare" resources.arcgis.com/en/help/main/10.1/index.html#//…
mike

1
@MAP: sponsorizza uno sviluppatore o invia una richiesta di funzionalità e attendi la benevolenza degli altri. :)
Scro,

5

Penso che il più vicino che possa ottenere con le attuali abilità di QGIS sia usare l' effetto alone (o di sfondo) con il colore proveniente dalla tabella che si baserà sul valore di elevazione e sulla combinazione di colori identici a quelli usati per la griglia sottostante. Naturalmente questo non prenderebbe in considerazione la sfumatura e tutto il resto sotto l' alone nella mappa. Esempio di colore casuale: colore casuale per effetto alone delle etichette con un po 'di codice questo potrebbe essere riscritto come funzione per riflettere il colore della griglia.

In teoria dovrebbe essere possibile utilizzare lo schema di linea personalizzato e l'etichetta ripetizione + offset . Sfortunatamente non esiste un'impostazione di offset dell'etichetta.

  • dopo alcuni test è impossibile forzare QGIS a essere rigoroso nel posizionare le etichette nell'intervallo esatto e in nessun altro posto (+ offset offset mancante comunque)
  • è impossibile creare un motivo di linea personalizzato con zero mm affinché lo spazio abbia uno scostamento iniziale come 20 linee - 10 spazi - 70 linee - 0 spazi - quindi l'etichetta verrebbe posizionata ogni 100 mm con uno scostamento di 30 mm all'inizio - il che significa che l'etichetta sarebbe in il centro di ogni foro da 10 mm.

inserisci qui la descrizione dell'immagine


2

Di recente, dopo essermi imbattuto nello stesso problema, ho messo insieme uno script QGIS Python per eseguire il lavoro pesante. Lo script che include alcuni dati di test (Regno Unito), file Leggimi (Guida) e fogli di stile utilizzati è disponibile all'indirizzo https://github.com/pjgeng/Contour-Labels

In breve, lo script utilizza due livelli vettoriali come input: il livello contorno annotato e un livello "guide". Quest'ultimo è costituito da polilinee che intersecano i contorni nelle posizioni dell'etichetta desiderate.

Lo script funziona quindi in base alla distanza tra i contorni e all'intervallo del contorno dell'indice quali etichette applicare, aggiunge un valore di rotazione ai punti dell'etichetta e infine ritaglia il livello del contorno originale per produrre gli spazi.

Primo piano del risultato finale.

L'approccio funziona particolarmente bene qualora l'utente debba produrre mappe di contorno a intervalli diversi nella stessa area (ovvero le guide non cambiano). Uno svantaggio è l'incapacità di modificare la posizione dell'etichetta al termine dello script. Per questo l'utente dovrebbe regolare le linee guida e rieseguire lo script rispetto all'input originale. In precedenza ho lavorato molto con i buffer attorno alle etichette per creare l'effetto interrotto, ma questo si è rivelato esteticamente sgradevole sulle mappe guidate dai dati vettoriali.

Purtroppo non posso aggiungere altre foto in questo momento per documentare o illustrare ulteriormente il processo.

PS: se si utilizzano gli strati di stile forniti nel repository, potrebbe essere necessario "attivare" i campi personalizzati per "Rotazione", "Mostra etichetta" e "Mostra sempre" nel menu di etichettatura. Su alcune installazioni di QGIS, queste vengono applicate automaticamente dal foglio di stile: non ho ancora scoperto le cause.


2

Ecco un'altra soluzione al problema del mascheramento dell'etichetta di contorno QGIS, in cui utilizzo la funzionalità Spatialite di QGIS (attualmente QGIS 3.x) insieme a un generatore di geometria per il posizionamento dell'etichetta.

Questa soluzione molto dinamica ci consente di modificare immediatamente tutte le dimensioni del testo e le posizioni delle etichette e sopravvive persino all'esportazione di un vettore PDF!

inserisci qui la descrizione dell'immagineinserisci qui la descrizione dell'immagineinserisci qui la descrizione dell'immagineinserisci qui la descrizione dell'immagine

Per renderlo possibile abbiamo bisogno delle seguenti parti:

  1. Un livello vettoriale “LINESTRING” o “MULTILINESTRING” chiamato “contorni” con 2 campi: “fid” (Interger64 - chiave primaria), “elev” (stringa)
  2. Un livello vettoriale “LINESTRING” chiamato “scratch_lines” (vedi linee rosse nell'immagine)
  3. Una tabella senza geometria chiamata "impostazioni" per memorizzare la dimensione globale dell'etichetta del contorno (questa è una soluzione semplice, perché QGIS non può usare le variabili di progetto nelle query SQL ormai): "fid" (Integer64 - chiave primaria), "variabile" (String), “value” (String)

inserisci qui la descrizione dell'immagine

  1. Un livello virtuale chiamato ie "contours_with_labels" con uno stile basato su regole:

    • Regola 1: "etichetta" = 1 ... linea semplice, opacità 0%
    • Regola 2: ELSE ... linea semplice

    • e un testo condizionale dell'etichetta per la Regola 1:

      CASO QUANDO etichetta = 1 THEN elev ELSE '' END

    • con un generatore di geometria per il posizionamento del testo:

      make_line (start_point ($ geometry), end_point ($ geometry))

    • e una stringa di espressione per la dimensione del testo variabile:

      attributo (get_feature ('settings', 'variabile', 'contourlabel_size'), 'value')

e ultimo ma non meno importante, ecco la query SQL per il livello virtuale:

------------------------------------------------------------------------
-- select all contour lines that do not intersect any scratch lines
------------------------------------------------------------------------
select c.geometry,c.elev,0 as label 
from contours c,
       (select st_union(geometry) as geom from scratch_lines) as scr 
where not st_intersects(c.geometry,scr.geom)
------------------------------------------------------------------------

UNION

--------------------------------------------------------------------------------------------------------
-- create buffers around all scratch lines (bufferwidth = length(elevation_text) * txtsize/3),
-- get st_difference between contour lines and buffers
-- and set attribute "label" to 0
--------------------------------------------------------------------------------------------------------
select st_difference(c.geometry,buf.geom) as geom,c.elev,0 as label 
from 
  (select c.fid,st_union(st_buffer(scr.geometry,length(c.elev) * txtsize.value / 3)) as geom 
      from scratch_lines scr, 
              contours c, 
              (select cast(value as integer) as value from settings where variable = 'contourlabel_size') txtsize 
      where st_intersects(scr.geometry,c.geometry) 
      group by c.fid) as buf,
  contours c 
where c.fid = buf.fid
group by c.fid
--------------------------------------------------------------------------------------------------------

UNION

--------------------------------------------------------------------------------------------------------
-- create buffers around all scratch lines (bufferwidth = length(elevation_text) * txtsize/3),
-- get st_intersection between contour lines and buffers
-- and set attribute "label" to 1
--------------------------------------------------------------------------------------------------------
select st_intersection(st_buffer(scr.geometry,length(c.elev) * txtsize.value / 3),c.geometry) as geom,c.elev,1 as label 
from scratch_lines scr,
        contours c,
        (select cast(value as integer) as value from settings where variable = 'contourlabel_size') txtsize 
where st_intersects(c.geometry,scr.geometry)

Questo è tutto.

Mille grazie a tutte queste persone entusiaste che lo hanno reso possibile!


Devo dire che sono impressionato dal risultato. Fino a quando non avremo un'opzione integrata (se mai), questo è sicuramente il modo più pulito. Livelli virtuali in soccorso, di nuovo.
Gabriel C.

Sono stato davvero colpito da me stesso. Ma può sopportare strati di contorno davvero grandi?
christoph

E sono molto contento, dopo averlo testato, che funzioni anche con i dati in GeoPackages! Volevo verificare poiché è basato su Spatialite. Vorrei poter votare più di una volta ...
Gabriel C.

IMHO, è indipendente da qualsiasi formato di file, perché la query è in esecuzione all'interno di QGIS. Quindi dovrebbe funzionare anche con CSV.
christoph

Sembra che non sia la fine della storia. Oggi, dopo una ricerca, mi sono reso conto che possiamo usare le funzioni di espressione QGIS all'interno della query SQL del livello virtuale: gis.stackexchange.com/questions/320991/… . Quindi c'è molto altro a venire, che accelererà il mascheramento delle etichette (sto pensando a query dipendenti dalla scala o a un migliore utilizzo degli indici spaziali).
christoph

1

Ti ricordi questa discussione Martin? L'unico modo in cui mi viene in mente di avvicinarmi a una soluzione al tuo problema sarebbe quello di sovrapporre il tuo livello del contorno con un livello del contorno ritagliato, usarlo per l'etichettatura e cambiare il colore della linea in qualcosa di neutro che maschererebbe i contorni sotto le etichette, si spera senza essere troppo invadenti. N.

Aggiunto in seguito: potrebbe valere la pena guardare anche questa discussione , la seconda risposta. Forse rompere le linee di contorno potrebbe essere una risposta, forse usando lo strato buffer usato per tagliare i contorni?


1

Per rendere le etichette più perfette, ho modificato la query SQL del livello virtuale per rispettare le linee di scratch che corrono parallele alle linee di contorno (vedere la soluzione di seguito):

Vecchia versione inserisci qui la descrizione dell'immagine

Nuova versione inserisci qui la descrizione dell'immagine

Ed ecco il nuovo SQL per il livello virtuale:

------------------------------------------------------------------------
-- select all contour lines that do not intersect any scratch lines
------------------------------------------------------------------------
select c.geometry,c.elev,0 as label 
from contours c,
   (select st_union(geometry) as geom from scratch_lines) as scr 
where not st_intersects(c.geometry,scr.geom)
------------------------------------------------------------------------

UNION

--------------------------------------------------------------------------------------------------------
-- create buffers around all intersection points (bufferwidth = length(elevation_text) * txtsize/2.5),
-- get st_difference between contour lines and buffers
-- and set attribute "label" to 0
--------------------------------------------------------------------------------------------------------
select st_difference(c.geometry,buf.geom) as geom,c.elev,0 as label 
from contours c,
(select c.fid,st_union(st_buffer(st_intersection(c.geometry,scr.geometry),length(c.elev) * txtsize.value / 3)) as geom
from contours c, scratch_lines scr, (select cast(value as integer) as value from settings where variable = 'contourlabel_size') txtsize
where st_intersects(c.geometry,scr.geometry)
group by c.fid) as buf
where c.fid = buf.fid
--------------------------------------------------------------------------------------------------------

UNION

--------------------------------------------------------------------------------------------------------
-- create buffers around all intersection points (bufferwidth = length(elevation_text) * txtsize/2.5),
-- get st_intersection between contour lines and buffers
-- and set attribute "label" to 1
--------------------------------------------------------------------------------------------------------
select st_intersection(c.geometry,st_buffer(st_intersection(c.geometry,scr.geometry),length(c.elev) * txtsize.value / 3)) as geom,c.elev,1 as label 
from contours c, 
 scratch_lines scr,
 (select cast(value as integer) as value from settings where variable = 'contourlabel_size') txtsize 
where st_intersects(c.geometry,scr.geometry)

1

Un piccolo addendum relativo alla domanda originale.

Per tutti coloro che non sono consapevoli del fatto che possiamo utilizzare lo stile "Generatore di geometria" per semplificare e uniformare le nostre linee di contorno in QGIS 3.10:

smooth (semplifica ($ geometry, 2), 2)

inserisci qui la descrizione dell'immagine


0

Voce del blog ESRI: http://blogs.esri.com/esri/arcgis/2011/11/28/variable-depth-masking-contour-label-example/

La mascheratura a profondità variabile per le etichette dei contorni prevede tre passaggi:

1creare l'annotazione dalle etichette, 2utilizzare lo strumento Maschere struttura delle funzioni per creare maschere e 3utilizzare le Opzioni di disegno avanzate> Impostazioni di mascheratura per specificare quali livelli verranno mascherati dalle maschere.


Questo mostra come potrebbe essere implementato, ma in realtà non risponde alla domanda.
underdark
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.