¿Cómo interrumpir las líneas de contorno debajo de las etiquetas de elevación (en lugar de usar topes de etiquetas)?

32

¿Hay alguna manera de interrumpir una línea de contorno debajo de una etiqueta de elevación?

ingrese la descripción de la imagen aquí

MAPA
fuente
ArcGIS? QGIS? ¿Personalizado?
Ragi Yaser Burhum
1
Yo uso qgis para el etiquetado del contorno
MAP
¿Aceptarías una respuesta que requiera PostGIS?
Scro
3
desafortunadamente: no :) Pero, ¿hay alguna manera de resolver el problema con PostGIS?
MAPA

Respuestas:

22

Sí, factible Normalmente sugeriría un búfer parcialmente transparente, pero veo por qué quieres hacer esto cartográficamente.

Esto podría ser lento, y debe decidir manualmente dónde quiere que vayan las etiquetas, pero cartográficamente hablando, ¡eso no es algo malo!

Aquí hay una captura de pantalla ...

Como puede ver, no hay amortiguadores. La trama debajo no se ve afectada. He incluido líneas de contorno intermedias más delgadas y las he diseñado para que solo se muestren cuando ELEV% 50 <> 0

ejemplo de líneas de contorno interrumpidas

Lo hice en QGIS 2.12 ... su millaje puede variar con versiones anteriores.

Supongo que aquí tiene un campo "ELEV" en cada línea de contorno.

Segmentar las líneas de contorno

  1. Utilice el procesamiento y el algoritmo GRASS v.split.length para dividir sus contornos en segmentos de igual longitud. Debe elegir una longitud que se acerque al tamaño de su etiqueta en unidades de mapa, suponiendo que esté usando metros. Aquí usé 200m.

    Tenga cuidado con esto, ya que hará que su archivo sea mucho, mucho más grande (tenga en cuenta que la función cuenta en la captura de pantalla).

    Para evitar esto, es posible que desee generar solo las líneas de contornos que desea diseñar (por ejemplo, cada 50 o 100 metros) para evitar el procesamiento de todas las líneas de contorno intermedias.

  2. A esta capa, agregue un campo entero de 1 dígito llamado showLabel . Por defecto a 0 o NULL.

  3. Cambie la etiqueta para que solo se muestre en un segmento donde este campo esté establecido en 1. Use esto para la expresión de texto de la etiqueta ...

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

    Creo que si (expresión, valor verdadero, valor falso) es bastante nuevo; si usa una versión anterior, puede usar CASE-ELSE

  4. Cambie el estilo de línea para que todos los segmentos de longitud fija se dibujen, excepto aquellos segmentos donde se muestra la etiqueta. Por lo tanto, use la representación basada en reglas con dos reglas

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

    Ahora, todos los contornos se mostrarán de manera predeterminada, pero sin etiquetas.

    Edite manualmente segmentos donde desea mostrar etiquetas

    Vaya al modo de edición y seleccione manualmente los segmentos donde desea que se muestren los valores de contorno, y establezca el valor showLabelen 1 para las características seleccionadas. Puede usar Ctrl+ select (en Ubuntu / Win, Cmd+ Ctrl+ Click / en Mac?) Para seleccionar múltiples segmentos para acelerar las cosas.

    Esto ahora debería 'recortar' los contornos donde desea que se muestren las etiquetas, y las etiquetas se mostrarán en los huecos.

En este caso, mi configuración de etiqueta fue:

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

¡Espero que ayude!

Steven Kay
fuente
55
Esta es la única solución totalmente funcional que puedo imaginar. Aunque es muy doloroso si hay muchas etiquetas, no me puedo imaginar haciendo todos mis mapas de cabezas de agua subterránea (miles por año) de esta manera. Sería genial si en el futuro esto se puede lograr a través del estilo, ya que lo mejor sería un patrón de línea personalizado y repetición de etiqueta + desplazamiento.
Miro
2
Solo algunas ideas para facilitar la tarea: para seleccionar los múltiples segmentos para dibujar la etiqueta, Seleccionar por polígono o Seleccionar a mano alzada puede ser útil. Además, otro enfoque sería crear una capa de línea de cero para dibujar líneas que intercepten los contornos, y luego hacer una selección por ubicación.
Alexandre Neto
7

Uso la opción "Buffer" en la pestaña "Configuración de etiqueta". (Usando el botón de etiquetas, no la opción de etiquetas antiguas en el cuadro de diálogo de propiedades de capa). Esto no borra la línea de contorno, como imagino que quieres hacer, pero hace que la etiqueta sea legible.

Scro
fuente
44
Nunca lo pensé antes, pero sería conveniente si en lugar de asignar un color para el búfer, pudieras elegir aplicarlo como un "golpe de gracia" a las capas seleccionadas.
Scro
55
La última versión de QGIS tiene buffers transparentes para que pueda reducir el impacto en otras partes del mapa.
Nathan W
1
@MAP Un golpe de gracia borra los píxeles debajo de él. Si esa fuera una opción, en este caso elegiría eliminar la capa de contorno.
Scro
1
nocaut - el término esri es "enmascarar" resources.arcgis.com/en/help/main/10.1/index.html#//…
mike
1
@MAP: patrocine a un desarrollador o envíe una solicitud de función y espere la benevolencia de los demás. :)
Scro
5

Creo que lo más cercano que puede estar con las habilidades actuales de QGIS es usar el efecto de halo (o fondo) con el color procedente de la tabla, que se basará en el valor de elevación y el esquema de color igual al utilizado para la cuadrícula subyacente. Por supuesto, esto no tomaría en cuenta el sombreado y todo lo demás debajo del halo en el mapa. Ejemplo de color aleatorio: color aleatorio para efecto halo de etiquetas con un poco de código, esto podría reescribirse como función para reflejar el color de la cuadrícula.

En teoría, debería ser posible utilizar un patrón de línea personalizado y repetir la etiqueta + desplazamiento . Desafortunadamente no hay una configuración de desplazamiento de etiqueta.

  • Después de algunas pruebas, es imposible forzar a QGIS a ser estricto con la colocación de las etiquetas en el intervalo exacto y en ningún otro lugar (de todos modos, falta el desplazamiento inicial)
  • es imposible crear un patrón de línea personalizado con cero mm para que el espacio tenga un desplazamiento inicial como 20 líneas - 10 espacios - 70 líneas - 0 espacios - por lo que la etiqueta se colocaría cada 100 mm con un desplazamiento de 30 mm al principio, lo que significa que la etiqueta estaría en el centro de cada agujero de 10 mm.

ingrese la descripción de la imagen aquí

Miró
fuente
2

Después de encontrarme con el mismo problema recientemente, armé un script QGIS Python para llevar a cabo el trabajo pesado. El guión que incluye algunos datos de prueba (Reino Unido), Léame (Guía) y hojas de estilo utilizadas se puede encontrar en https://github.com/pjgeng/Contour-Labels

En resumen, el script utiliza dos capas vectoriales como entrada: la capa de contorno anotada y una capa de "guías". Este último consiste en polilíneas que intersecan los contornos en las ubicaciones de etiquetas deseadas.

La secuencia de comandos luego se basa en la distancia entre los contornos y el intervalo de contornos de índice que las etiquetas a aplicar, agrega un valor de rotación a los puntos de la etiqueta y eventualmente recorta la capa de contorno original para producir los espacios.

Primer plano del resultado final.

El enfoque funciona particularmente bien si el usuario necesita producir mapas de contorno a diferentes intervalos en la misma área (es decir, las guías no cambian). Un inconveniente es la incapacidad de cambiar la posición de la etiqueta una vez que el guión ha finalizado. Para esto, el usuario tendría que ajustar las líneas de guía y volver a ejecutar el script contra la entrada original. Anteriormente trabajé mucho con las memorias intermedias alrededor de las etiquetas para crear el efecto interrumpido, pero esto resultó ser estéticamente desagradable en los mapas basados ​​en datos vectoriales.

Lamentablemente, no puedo agregar más imágenes en este momento para documentar o ilustrar el proceso más.

PD: Si usa las capas de estilo proporcionadas en el repositorio, los usuarios pueden necesitar "activar" los campos personalizados para "Rotación", "Mostrar etiqueta" y "Mostrar siempre" en el menú de etiquetado. En algunas instalaciones de QGIS, estos se aplican automáticamente desde la hoja de estilo; todavía no he descubierto qué causa esto.

Phil G
fuente
2

Aquí hay otra solución para el problema de enmascaramiento de etiquetas de contorno QGIS, donde aprovecho la funcionalidad Spatialite de QGIS (actualmente QGIS 3.x) junto con un generador de geometría para la colocación de etiquetas.

Esta solución muy dinámica nos permite cambiar todos los tamaños de texto de etiquetas y posiciones de etiquetas de forma inmediata, ¡e incluso sobrevive a una exportación de vectores PDF!

ingrese la descripción de la imagen aquíingrese la descripción de la imagen aquíingrese la descripción de la imagen aquíingrese la descripción de la imagen aquí

Para que esto sea posible, necesitamos las siguientes partes:

  1. Una capa vectorial "LINESTRING" o "MULTILINESTRING" llamada "contornos" con 2 campos: "fid" (Interger64 - clave principal), "elev" (String)
  2. Una capa vectorial "LINESTRING" llamada "scratch_lines" (ver líneas rojas en la imagen)
  3. Una tabla sin geometría llamada "configuración" para almacenar el tamaño global de la etiqueta de contorno (esta es una solución simple, porque QGIS no puede usar variables de proyecto en consultas SQL por ahora): "fid" (Integer64 - clave primaria), "variable" (Cadena), "valor" (Cadena)

ingrese la descripción de la imagen aquí

  1. Una capa virtual llamada, es decir, "contours_with_labels" con estilo basado en reglas:

    • Regla 1: "etiqueta" = 1 ... línea simple, opacidad 0%
    • Regla 2: ELSE ... línea simple

    • y un texto de etiqueta condicional para la Regla 1:

      CASO CUANDO etiqueta = 1 LUEGO once más '' FIN

    • con un generador de geometría para la colocación de texto:

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

    • y una cadena de expresión para el tamaño de texto variable:

      atributo (get_feature ('configuración', 'variable', 'contourlabel_size'), 'valor')

y por último pero no menos importante, aquí va la consulta SQL para la capa virtual:

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

Eso es.

¡Muchas gracias a todas estas personas entusiastas que hacen esto posible!

christoph
fuente
Debo decir que estoy impresionado con el resultado. Hasta que tengamos una opción integrada (si alguna vez), esta es definitivamente la forma más limpia. Capas virtuales al rescate, nuevamente.
Gabriel C.
De hecho, estaba impresionado por mí mismo. Pero, ¿puede soportar capas de contorno realmente grandes?
Christoph
¡Y estoy muy contento, después de probarlo, de que también funciona con datos en GeoPackages! Quería verificarlo ya que está basado en Spatialite. Ojalá pudiera votar más de una vez ...
Gabriel C.
En mi humilde opinión, es independiente de cualquier formato de archivo, porque la consulta se ejecuta dentro de QGIS. Por lo tanto, incluso debería funcionar con CSV.
christoph hace
Parece que no es el final de la historia. Después de una investigación hoy, me di cuenta de que podemos usar funciones de expresión QGIS dentro de la consulta SQL de capa virtual: gis.stackexchange.com/questions/320991/… . Así que hay mucho más por venir, lo que acelerará el enmascaramiento de la etiqueta (estoy pensando en consultas dependientes de la escala o un mejor uso de los índices espaciales).
christoph hace
1

Te acuerdas de esto hilo Martin? La única forma en que puedo pensar para acercarme a una solución a su problema sería superponer su capa de contorno con una capa de contorno recortada, usar esto para etiquetar y cambiar el color de la línea a algo neutral que enmascare los contornos debajo de las etiquetas, uno espera sin ser demasiado intrusivo. NORTE.

Agregado más tarde: podría valer la pena mirar este hilo también, la segunda respuesta. ¿Quizás romper las líneas de contorno podría ser una respuesta, quizás usando la capa de amortiguación utilizada para recortar los contornos?

nhopton
fuente
1

Para hacer que las etiquetas sean más perfectas, cambié la consulta SQL de la capa virtual para respetar las líneas de borrador que corren paralelas a las líneas de contorno (consulte la solución a continuación):

Versión antigua ingrese la descripción de la imagen aquí

Nueva versión ingrese la descripción de la imagen aquí

Y aquí está el nuevo SQL para la capa virtual:

------------------------------------------------------------------------
-- 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
fuente
1

Una pequeña adición relacionada con la pregunta original.

Para todos aquellos que no son conscientes del hecho de que podemos usar el estilo "Generador de geometría" para simplificar y suavizar nuestras líneas de contorno en QGIS 3.10:

liso (simplificar ($ geometry, 2), 2)

ingrese la descripción de la imagen aquí

christoph
fuente
0

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

El enmascaramiento de profundidad variable para etiquetas de contorno implica tres pasos:

1creando anotaciones a partir de las etiquetas, 2 usando la herramienta Máscaras de contorno de entidades para crear máscaras, y 3 usando las Opciones avanzadas de dibujo> Configuración de enmascaramiento para especificar qué capas enmascararán las máscaras.

Jenny
fuente
Esto muestra cómo se podría implementar, pero en realidad no responde la pregunta.
oscuro