Como interromper linhas de contorno abaixo dos rótulos de elevação (em vez de usar buffers de rótulo)?


32

Existe uma maneira de interromper uma linha de contorno abaixo de um rótulo de elevação?

insira a descrição da imagem aqui


ArcGIS? QGIS? Personalizadas?
Ragi Yaser Burhum

1
Eu uso qgis para a rotulagem de contorno
MAP

Você aceitaria uma resposta que exija PostGIS?
Scro

3
infelizmente: não :) Mas, existe uma maneira de resolver o problema com o PostGIS?
MAP

Respostas:


22

Sim, factível. Normalmente, sugiro um buffer parcialmente transparente, mas vejo por que você deseja fazer isso cartograficamente.

Isso pode ser lento, e você precisa decidir manualmente para onde deseja que os rótulos cheguem - mas cartograficamente falando, isso não é uma coisa ruim!

Aqui está uma captura de tela ...

Como você pode ver, não há buffers. A varredura abaixo não é afetada. Incluí linhas de contorno intermediárias mais finas e as denomino para que sejam exibidas apenas quando ELEV% 50 <> 0

exemplo de linhas de contorno interrompidas

Fiz isso no QGIS 2.12 ... sua milhagem pode variar com as versões anteriores.

Presumo que aqui você tenha um campo "ELEV" em cada linha de contorno.

Segmentar as linhas de contorno

  1. Use o processamento e o algoritmo GRASS v.split.length para dividir seus contornos em segmentos de igual comprimento. Você precisa escolher um comprimento que seja próximo ao tamanho da sua etiqueta nas unidades do mapa, supondo que você esteja usando medidores. Aqui eu usei 200m.

    Tenha cuidado com isso, pois ele tornará seu arquivo muito, muito maior (observe o recurso na captura de tela).

    Para contornar isso, você pode gerar apenas as linhas de contorno que deseja estilizar (por exemplo, a cada 50 ou 100 metros) para evitar o processamento de todas as linhas de contorno intermediárias.

  2. Para essa camada, adicione um campo inteiro de 1 dígito chamado showLabel . O padrão é 0 ou NULL.

  3. Altere o rótulo para mostrar apenas em um segmento em que esse campo esteja definido como 1. Use isso para a expressão de texto do rótulo ...

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

    Eu acho que se (expressão, valor verdadeiro, valor falso) é relativamente novo; se estiver usando uma versão mais antiga, você poderá usar o CASE-ELSE

  4. Altere o estilo da linha para que todos os segmentos de comprimento fixo sejam desenhados, exceto os segmentos em que o rótulo é exibido. Portanto, use a renderização baseada em regras com duas regras

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

    Agora, todos os contornos serão mostrados por padrão, mas nenhum rótulo.

    Edite manualmente os segmentos nos quais deseja mostrar rótulos

    Entre no modo de edição e selecione manualmente os segmentos onde deseja que os valores do contorno sejam exibidos e defina o valor showLabelcomo 1 para os recursos selecionados. Você pode usar Ctrl+ select (no Ubuntu / Win, Cmd+ Ctrl+ Click / no Mac?) Para selecionar vários segmentos para acelerar as coisas.

    Agora, isso deve "recortar" os contornos onde você deseja que os rótulos sejam exibidos, e os rótulos aparecerão nas lacunas.

Nesse caso, minhas configurações de etiqueta foram:

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

Espero que ajude!


5
Esta é a única solução totalmente funcional que posso imaginar. Muito doloroso, porém, se houver muitos rótulos, não consigo imaginar fazer todos os meus mapas das cabeças de águas subterrâneas (milhares por ano) dessa maneira. Seria ótimo se, no futuro, isso for possível através do estilo - pois o melhor seria o padrão de linha personalizado e a repetição e deslocamento da etiqueta.
Miro

2
Apenas algumas idéias para facilitar a tarefa: Para selecionar os vários segmentos para desenhar o rótulo, Selecionar por polígono ou Selecionar à mão livre pode ser útil. Além disso, outra abordagem seria criar uma camada de linha de rascunho para desenhar linhas que interceptem os contornos e, em seguida, selecione Selecionar por local.
Alexandre Neto

7

Eu uso a opção "Buffer" na guia "Configuração da etiqueta". (Usando o botão de etiquetas, não a opção de etiquetas antigas na caixa de diálogo de propriedades da camada.) Isso não apaga a linha de contorno, como eu imagino que você queira, mas torna a etiqueta legível.


4
Eu nunca pensei nisso antes, mas seria conveniente se, em vez de atribuir uma cor ao buffer, você pudesse aplicá-lo como um 'nocaute' nas camadas selecionadas.
Scro

5
A versão mais recente do QGIS possui buffers transparentes para que você possa reduzir o impacto em outras partes do mapa.
23713 Nathan W

1
@ MAP Um nocaute apaga os pixels abaixo dele. Se isso fosse uma opção, nesse caso, você escolheria nocautear a camada de contorno.
Scro

1
nocaute - o termo esri é "mascarar" resources.arcgis.com/en/help/main/10.1/index.html#//…
mike

1
@MAP - Patrocine um desenvolvedor ou envie uma solicitação de recurso e aguarde a benevolência de outros. :)
Scro 27/02

5

Acho que o mais próximo possível das habilidades atuais do QGIS é usar o efeito halo (ou plano de fundo) com cores originadas da tabela, que serão baseadas no valor de elevação e no esquema de cores iguais aos usados ​​na grade subjacente. É claro que isso não levaria em conta a colina e tudo o mais abaixo da auréola no mapa. Exemplo aleatório de cores: cor aleatória para efeito halo dos rótulos Com um pouco de código, isso pode ser reescrito como função para refletir a cor da grade.

Em teoria, deve ser possível usar padrão de linha personalizado e repetição de etiqueta + deslocamento . Infelizmente, não há configuração de deslocamento de etiqueta.

  • após alguns testes, é impossível forçar o QGIS a ser rigoroso ao colocar os rótulos no intervalo exato e em nenhum outro lugar (+ ausência do deslocamento inicial de qualquer maneira)
  • é impossível criar um padrão de linha personalizado com zero mm para que o espaço tenha deslocamento inicial como 20 linhas - 10 espaços - 70 linhas - 0 espaço - para que a etiqueta seja colocada a cada 100 mm com deslocamento de 30 mm no início - o que significa que a etiqueta estaria em no meio de cada furo de 10 mm.

insira a descrição da imagem aqui


2

Depois de encontrar o mesmo problema recentemente, montei um script QGIS Python para realizar o trabalho pesado. O script, incluindo alguns dados de teste (REINO UNIDO), Leia-me (Guia) e folhas de estilos usadas, pode ser encontrado em https://github.com/pjgeng/Contour-Labels

Em resumo, o script usa duas camadas de vetor como entrada - a camada de contorno anotada e uma camada "guias". O último consiste em polilinhas que cruzam os contornos nos locais de etiqueta desejados.

O script então funciona com base na distância entre os contornos e o intervalo de contorno do índice que os rótulos serão aplicados, adiciona um valor de rotação aos pontos do rótulo e, eventualmente, corta a camada de contorno original para produzir as lacunas.

Closeup do resultado final.

A abordagem funciona particularmente bem caso o usuário precise produzir mapas de contorno em intervalos diferentes na mesma área (ou seja, os guias não mudam). Uma desvantagem é a incapacidade de alterar a posição do rótulo após a conclusão do script. Para isso, o usuário teria que ajustar as linhas de guia e executar novamente o script em relação à entrada original. Anteriormente, eu trabalhei muito com buffers em torno de rótulos para criar o efeito interrompido, mas isso acabou sendo esteticamente desagradável em mapas acionados por dados vetoriais.

Infelizmente, não posso adicionar mais fotos no momento para documentar ou ilustrar o processo.

PS: Se usar as camadas de estilo fornecidas no repositório, os usuários podem precisar "ativar" os campos personalizados para "Rotação", "Mostrar etiqueta" e "Sempre mostrar" no menu de etiquetas. Em algumas instalações do QGIS, elas são aplicadas automaticamente a partir da folha de estilo - ainda não descobri o que causa isso.


2

Aqui está outra solução para o problema de mascaramento de etiqueta de contorno do QGIS, em que aproveito a funcionalidade Spatialite do QGIS (atualmente QGIS 3.x) junto com um gerador de geometria para a colocação da etiqueta.

Esta solução muito dinâmica nos permite alterar todos os tamanhos de texto e posições de etiqueta imediatamente e até sobreviver a uma exportação de vetor em PDF!

insira a descrição da imagem aquiinsira a descrição da imagem aquiinsira a descrição da imagem aquiinsira a descrição da imagem aqui

Para tornar isso possível, precisamos das seguintes partes:

  1. Uma camada vetorial "LINESTRING" ou "MULTILINESTRING" denominada "contornos" com 2 campos: "fid" (Interger64 - chave primária), "elev" (String)
  2. Uma camada vetorial "LINESTRING" chamada "scratch_lines" (veja linhas vermelhas na figura)
  3. Uma tabela sem geometria chamada “settings” para armazenar o tamanho global do rótulo de contorno (esta é uma solução simples, porque o QGIS não pode usar variáveis ​​de projeto em consultas SQL agora): “fid” (Integer64 - chave primária), “variable” (String), "valor" (String)

insira a descrição da imagem aqui

  1. Uma camada virtual chamada ie "contours_with_labels" com estilo baseado em regras:

    • Regra 1: “label” = 1… linha simples, opacidade 0%
    • Regra 2: ELSE ... linha simples

    • e um texto de rótulo condicional para a Regra 1:

      CASE WHEN label = 1 THEN elev ELSE '' END

    • com um gerador de geometria para posicionamento do texto:

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

    • e uma String de expressão para o tamanho variável do texto:

      atributo (get_feature ('configurações', 'variável', 'contourlabel_size'), 'valor')

e por último mas não menos importante, aqui está a consulta SQL para a camada 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)

É isso aí.

Muito obrigado a todas essas pessoas entusiasmadas que tornam isso possível!


Devo dizer que estou impressionado com o resultado. Até que tenhamos uma opção integrada (se alguma vez), essa é definitivamente a maneira mais limpa. Camadas virtuais para o resgate, novamente.
Gabriel C.

Fiquei realmente impressionado comigo mesmo. Mas, pode suportar realmente grandes camadas de contorno?
christoph

E fico muito feliz, depois de testá-lo, que ele também funcione com dados nos GeoPackages! Eu queria verificar, pois é baseado no Spatialite. Gostaria de poder votar mais de uma vez ...
Gabriel C.

IMHO, é independente de qualquer formato de arquivo, porque a consulta está sendo executada dentro do QGIS. Por isso, deve até funcionar com CSV.
christoph

Parece que não é o fim da história. Após uma pesquisa de hoje, percebi que podemos usar as funções de expressão QGIS dentro da consulta SQL da camada virtual: gis.stackexchange.com/questions/320991/… . Portanto, há muito mais por vir, o que acelerará o mascaramento de rótulos (estou pensando em consultas dependentes de escala ou melhor uso de índices espaciais).
christoph

1

Você se lembra dessa discussão Martin? A única maneira de pensar em chegar perto de uma solução para o seu problema seria sobrepor sua camada de contorno com uma camada de contorno cortada, use isso para rotular e altere a cor da linha para algo neutro que oculte os contornos sob os rótulos, espera-se sem ser muito intrusivo. N.

Adicionado mais tarde: pode valer a pena olhar também para este tópico , a segunda resposta. Talvez quebrar as linhas de contorno possa ser uma resposta, talvez usando a camada de buffer usada para cortar os contornos?


0

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

O mascaramento de profundidade variável para etiquetas de contorno envolve três etapas:

1criando anotações nas etiquetas, 2utilizando a ferramenta Máscaras de estrutura de tópicos para criar máscaras e 3utilizando as opções Opções avançadas de desenho> Configurações de máscara para especificar quais camadas as máscaras irão mascarar.


Isso mostra como ele poderia ser implementado, mas na verdade não responde à pergunta.
underdark

0

Para tornar os rótulos mais perfeitos, alterei a consulta SQL da camada virtual para respeitar as linhas de arranque paralelas às linhas de contorno (consulte a solução abaixo):

Versão antiga insira a descrição da imagem aqui

Nova versão insira a descrição da imagem aqui

E aqui está o novo SQL para a camada 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)

0

Um pequeno adendo relacionado à pergunta original.

Para todos aqueles que não estão cientes do fato de que podemos usar o estilo "Gerador de geometria" para simplificar e suavizar nossas linhas de contorno no QGIS 3.10:

suave (simplificar ($ geometry, 2), 2)

insira a descrição da imagem aqui

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.