Comment interrompre les lignes de contour sous les étiquettes d'élévation (au lieu d'utiliser des tampons d'étiquettes)?

32

Est-il possible d'interrompre une ligne de contour sous une étiquette d'élévation?

entrez la description de l'image ici

CARTE
la source
ArcGIS? QGIS? Douane?
Ragi Yaser Burhum
1
J'utilise les qgis pour l'étiquetage des contours
MAP
Accepteriez-vous une réponse nécessitant PostGIS?
Scro
3
malheureusement: non :) Mais, existe-t-il un moyen de résoudre le problème avec PostGIS?
MAP

Réponses:

22

Oui, faisable Normalement, je suggérerais un tampon partiellement transparent, mais je vois pourquoi vous voulez le faire par cartographie.

Cela peut être lent et vous devez décider manuellement où vous voulez que les étiquettes aillent - mais sur le plan cartographique, ce n'est pas une mauvaise chose!

Voici une capture d'écran ...

Comme vous pouvez le voir, pas de tampons. Le raster en dessous n'est pas affecté. J'ai inclus des lignes de contour intermédiaires plus minces et les ai stylisées pour qu'elles ne soient affichées que lorsque ELEV% 50 <> 0.

exemple de lignes de contour interrompues

Je l'ai fait dans QGIS 2.12 ... votre kilométrage peut varier par rapport aux versions précédentes.

Je suppose ici que vous avez un champ "ELEV" sur chaque ligne de contour.

Segmenter les lignes de contour

  1. Utilisez le traitement et l’algorithme GRASS v.split.length pour scinder vos contours en segments de longueur égale. Vous devez choisir une longueur qui sera proche de la taille de votre étiquette en unités de carte, en supposant que vous utilisiez des mètres. Ici j'ai utilisé 200m.

    Soyez prudent avec ceci car cela rendra votre fichier beaucoup plus gros (notez que la fonctionnalité compte dans la capture d'écran).

    Pour éviter ce problème, vous pouvez générer uniquement les lignes de contour que vous souhaitez styler (par exemple, tous les 50 ou 100 mètres) pour éviter de traiter toutes les lignes de contour intermédiaires.

  2. A cette couche, ajoutez un champ entier à 1 chiffre appelé showLabel . La valeur par défaut est 0 ou NULL.

  3. Modifiez l'étiquette pour afficher uniquement sur un segment où ce champ est défini sur 1. Utilisez ceci pour l'expression de texte d'étiquette ...

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

    Je pense que si (expression, valeur vraie, valeur fausse) est relativement nouvelle; si vous utilisez une version plus ancienne, vous pouvez utiliser CASE-ELSE

  4. Modifiez le style de ligne afin que les segments de longueur fixe soient tous dessinés, à l' exception des segments pour lesquels l'étiquette est affichée. Utilisez donc le rendu basé sur des règles avec deux règles

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

    Maintenant, tous les contours seront affichés par défaut, mais pas d’étiquettes.

    Modifier manuellement les segments pour lesquels vous souhaitez afficher les étiquettes

    Passez en mode édition et sélectionnez manuellement les segments sur lesquels vous souhaitez afficher les valeurs de contour, puis définissez la valeur showLabelsur 1 pour les entités sélectionnées. Vous pouvez utiliser Ctrl+ select (sur Ubuntu / Win, Cmd+ Ctrl+ Click / sur Mac?) Pour sélectionner plusieurs segments afin d’accélérer les choses.

    Cela devrait maintenant «découper» les contours à l'endroit où vous souhaitez afficher les étiquettes, et les étiquettes s'afficheront dans les espaces.

Dans ce cas, mes paramètres d'étiquette étaient:

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

J'espère que ça t'as aidé!

Steven Kay
la source
5
C’est la seule solution pleinement opérationnelle que je puisse imaginer. Très pénible cependant, s'il y a beaucoup d'étiquettes, je ne peux pas imaginer faire toutes mes cartes de têtes d'eaux souterraines (des milliers par an) de cette façon. Ce serait formidable si, à l'avenir, cela est réalisable grâce au style, car le mieux serait un motif de trait personnalisé et une répétition d'étiquette + un décalage.
Miro
2
Quelques idées pour faciliter la tâche: Pour sélectionner plusieurs segments pour dessiner l’étiquette, Sélectionner par polygone ou Sélectionner à main levée peut être pratique. En outre, une autre approche consisterait à créer un calque de ligne à gratter pour tracer des lignes qui interceptent les contours, puis effectuer une sélection par emplacement.
Alexandre Neto
7

J'utilise l'option "Tampon" de l'onglet "Paramétrage d'étiquette". (Utiliser le bouton Étiquettes, et non l'ancienne option Étiquettes de la boîte de dialogue Propriétés de la couche.) Cela n'efface pas la ligne de contour, comme je suppose que vous voulez le faire, mais cela rend l'étiquette lisible.

Scro
la source
4
Je n'y avais jamais pensé auparavant, mais il serait pratique que, au lieu d'attribuer une couleur au tampon, vous puissiez choisir de l'appliquer en tant que "KO" aux calques sélectionnés.
Scro
5
La dernière version de QGIS dispose de tampons transparents vous permettant de réduire l'impact sur les autres parties de la carte.
Nathan W
1
@MAP Un KO efface les pixels en dessous. Si cela était une option, dans ce cas, vous choisiriez d’enlever le calque de contour.
Scro
1
knock-out - le terme esri est "masquant" ressources.arcgis.com/fr/help/main/10.1/index.html#//…
mike
1
@ MAP - Parrainez un développeur ou soumettez une demande de fonctionnalité et attendez la bienveillance des autres. :)
Scro
5

Je pense que le plus proche des capacités actuelles de QGIS consiste à utiliser un effet de halo (ou d’arrière-plan) avec une couleur provenant du tableau, qui sera basé sur la valeur d’altitude et le schéma de couleurs identique à celui utilisé pour la grille sous-jacente. Bien sûr, cela ne prendrait pas en compte l’ombrage et tout le reste en dessous du halo sur la carte. Exemple de couleur aléatoire: couleur aléatoire pour l'effet de halo des étiquettes avec un peu de code, cela pourrait être réécrit comme fonction pour refléter la couleur de la grille.

En théorie, il devrait être possible d'utiliser un motif de trait personnalisé et une répétition d'étiquette + un décalage . Malheureusement, il n'y a pas de paramètre de décalage d'étiquette.

  • après quelques tests, il est impossible de forcer QGIS à être strict en plaçant les étiquettes à un intervalle exact et nulle part ailleurs (+ décalage de départ manquant de toute façon)
  • il est impossible de créer un motif de ligne personnalisé avec un espace de 0 mm pour un décalage de départ de 20 mm - 10 espaces - 70 lignes - 0 espace - ainsi l'étiquette serait placée tous les 100 mm avec un décalage de 30 mm au début - signifiant que l'étiquette serait en au milieu de chaque trou de 10 mm.

entrez la description de l'image ici

Miro
la source
2

Après avoir rencontré le même problème récemment, j’ai mis au point un script QGIS Python pour effectuer le gros travail. Le script, y compris certaines données de test (UK), le fichier Readme (Guide) et les feuilles de style utilisées, est disponible à l' adresse https://github.com/pjgeng/Contour-Labels.

En bref, le script utilise deux couches vectorielles en entrée - la couche de contour annotée et une couche "guides". Ce dernier est constitué de polylignes intersectant les contours aux emplacements désirés des étiquettes.

Le script est ensuite élaboré en fonction de la distance entre les contours et de l’intervalle de contour d’index auquel les étiquettes doivent être appliquées, ajoute une valeur de rotation aux points de l’étiquette, puis coupe le calque de contour d’origine pour produire les espaces.

Gros plan du résultat final.

L'approche fonctionne particulièrement bien si l'utilisateur a besoin de produire des cartes de contours à différents intervalles dans la même zone (les guides ne changent pas). L'inconvénient est l'incapacité de modifier la position de l'étiquette une fois le script terminé. Pour cela, l'utilisateur devra ajuster les lignes de guidage et réexécuter le script avec l'entrée d'origine. Auparavant, j'avais beaucoup travaillé avec les tampons autour des étiquettes pour créer l'effet interrompu, mais cela s'est avéré esthétiquement désagréable sur les cartes vectorielles.

Malheureusement, je ne peux ajouter aucune image pour le moment pour documenter ou illustrer davantage le processus.

PS: Si vous utilisez les couches de style fournies dans le référentiel, les utilisateurs devront peut-être "activer" les champs personnalisés pour "Rotation", "Afficher le libellé" et "Toujours afficher" dans le menu libellé. Sur certaines installations de QGIS, celles-ci sont appliquées automatiquement à partir de la feuille de style - je n’ai pas encore découvert la cause de ce problème.

Phil G
la source
2

Voici une autre solution au problème de masquage d'étiquette de contour QGIS, dans laquelle j'utilise la fonctionnalité Spatialite de QGIS (actuellement QGIS 3.x) avec un générateur de géométrie pour le placement d'étiquette.

Cette solution très dynamique nous permet de modifier immédiatement toutes les tailles et positions de libellé d'étiquettes, et même de survivre à une exportation vectorielle au format PDF!

entrez la description de l'image icientrez la description de l'image icientrez la description de l'image icientrez la description de l'image ici

Pour rendre cela possible, nous avons besoin des pièces suivantes:

  1. Un calque vectoriel “LINESTRING” ou “MULTILINESTRING” appelé “contours” à 2 champs: “fid” (Interger64 - clé primaire), “elev” (String)
  2. Une couche vectorielle "LINESTRING" appelée "scratch_lines" (voir les lignes rouges dans l'image)
  3. Un tableau sans géométrie appelé "paramètres" pour stocker la taille globale de l'étiquette de contour (solution simple, car QGIS ne peut pas utiliser les variables du projet à ce stade): "fid" (Integer64 - clé primaire), "variable" (Chaîne), “valeur” (Chaîne)

entrez la description de l'image ici

  1. Une couche virtuelle appelée «contours_with_labels» avec un style basé sur des règles:

    • Règle 1: “label” = 1… ligne simple, opacité 0%
    • Règle 2: ELSE… simple ligne

    • et un texte d'étiquette conditionnel pour la règle 1:

      CAS QUAND étiquette = 1 ALORS elev ELSE '' END

    • avec un générateur de géométrie pour le placement de texte:

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

    • et une chaîne d'expression pour la taille de texte variable:

      attribut (get_feature ('settings', 'variable', 'contourlabel_size'), 'value')

et enfin, voici la requête SQL pour la couche virtuelle:

------------------------------------------------------------------------
-- 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)

C'est ça.

Un grand merci à toutes ces personnes enthousiastes qui rendent cela possible!

christoph
la source
Je dois dire que je suis impressionné par le résultat. Jusqu'à ce que nous obtenions une option intégrée (si jamais), c'est définitivement le moyen le plus propre. Les couches virtuelles à la rescousse, encore.
Gabriel C.
J'étais vraiment impressionné par moi-même. Mais peut-il supporter de très grandes couches de contour?
christoph
Et je suis très heureux, après l'avoir testé, que cela fonctionne également avec les données de GeoPackages! Je voulais vérifier car il est basé sur Spatialite. Si seulement je pouvais voter plus d'une fois ...
Gabriel C. Il y a
IMHO, il est indépendant de tout format de fichier, car la requête s'exécute dans QGIS. Donc, cela devrait même fonctionner avec CSV.
christoph il y a
On dirait que ce n'est pas la fin de l'histoire. Après une recherche effectuée aujourd’hui, j’ai réalisé que nous pouvions utiliser les fonctions d’expression QGIS dans la requête SQL de la couche virtuelle: gis.stackexchange.com/questions/320991/… . Il y a donc beaucoup plus à venir, ce qui accélérera le masquage d'étiquette (je pense aux requêtes dépendantes de l'échelle ou à une meilleure utilisation des index spatiaux).
christoph il y a
1

Vous souvenez-vous de ce fil Martin? Le seul moyen auquel je puisse penser pour trouver une solution à votre problème serait de superposer votre calque de contour avec un calque de contour découpé, utilisez-le pour l'étiquetage et modifiez la couleur de trait en une couleur neutre masquant les contours sous les étiquettes, on espère sans être trop intrusif. N.

Ajouté plus tard: il pourrait être intéressant de regarder ce fil aussi, la deuxième réponse. Peut-être que casser les lignes de contour pourrait être une solution, peut-être en utilisant la couche tampon utilisée pour couper les contours?

Nhopton
la source
1

Pour rendre les étiquettes plus parfaites, j'ai modifié la requête SQL de la couche virtuelle afin de respecter les lignes de grattage parallèles aux lignes de contour (voir la solution ci-dessous):

Ancienne version entrez la description de l'image ici

Nouvelle version entrez la description de l'image ici

Et voici le nouveau SQL pour la couche virtuelle:

------------------------------------------------------------------------
-- 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)
christoph
la source
1

Un petit addenda lié à la question initiale.

Pour tous ceux qui ne sont pas conscients du fait que nous pouvons utiliser le style "Générateur de géométrie" pour simplifier et adoucir nos lignes de contour dans QGIS 3.10:

smooth (simplify ($ geometry, 2), 2)

entrez la description de l'image ici

christoph
la source
0

Entrée de blog ESRI: http://blogs.esri.com/esri/arcgis/2011/11/28/variable-depth-masking-contour-label-example/

Le masquage à profondeur variable pour les étiquettes de contour comprend trois étapes:

1 créez des annotations à partir des étiquettes, 2 utilisez l'outil Masques de structure pour créer des masques et 3 utilisez les paramètres Options de dessin avancées> Masquage pour spécifier les calques que les masques masqueront.

Jenny
la source
Cela montre comment cela pourrait être mis en œuvre, mais cela ne répond pas vraiment à la question.
underdark