Existe uma maneira de interromper uma linha de contorno abaixo de um rótulo de elevação?
Existe uma maneira de interromper uma linha de contorno abaixo de um rótulo de elevação?
Respostas:
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
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
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.
Para essa camada, adicione um campo inteiro de 1 dígito chamado showLabel . O padrão é 0 ou NULL.
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
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 showLabel
como 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!
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.
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: 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.
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.
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.
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!
Para tornar isso possível, precisamos das seguintes partes:
Uma camada virtual chamada ie "contours_with_labels" com estilo baseado em regras:
Regra 2: ELSE ... linha simples
e um texto de rótulo condicional para a Regra 1:
CASE WHEN label = 1 THEN elev ELSE '' END
make_line (start_point ($ geometry), end_point ($ geometry))
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!
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?
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.
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):
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)