如何中断高程标签下方的轮廓线(而不是使用标签缓冲区)?


Answers:


22

是的,可行。通常,我建议使用部分透明的缓冲区,但是我明白了为什么要按制图方式这样做。

这可能很慢,并且您需要手动确定标签的位置-但从制图的角度来讲,这不是一件坏事!

这是截图...

如您所见,没有缓冲区。下方的栅格不受影响。我包括了较细的中间轮廓线,并对它们进行了样式设置,以便仅在ELEV%50 <> 0时显示它们

example of interrupted contour lines

我已经在QGIS 2.12中完成了此操作……您的里程可能会因早期版本而异。

我假设您在每条轮廓线上都有一个“ ELEV”字段。

分割轮廓线

  1. 使用处理和GRASS算法v.split.length将轮廓分成等长的段。假设您使用的是米,则需要选择一个与地图单位的标签大小相近的长度。在这里我用了200m。

    请注意这一点,因为它会使文件大得多(请注意屏幕快照中的功能计数)。

    为了解决这个问题,您可能只想生成想要设置样式的轮廓线(例如,每50或100米),以避免处理所有中间轮廓线。

  2. 在此层中,添加一个称为showLabel的1位整数字段。默认为0或NULL。

  3. 将标签更改为仅显示在该字段设置为1的句段上。将其用于标签文本表达式...

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

    我认为if(expression,true-value,false-value)是相当新的;如果使用旧版本,则可以使用CASE-ELSE

  4. 更改线条样式,以绘制固定长度的线段,显示标签的线段除外。因此,请使用基于规则的渲染和两个规则

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

    现在,默认情况下将显示所有轮廓,但没有标签。

    手动编辑要在其中显示标签的细分

    进入编辑模式并手动选择要显示轮廓值的线段,然后将showLabel所选特征的值设置为1。您可以使用Ctrl+选择(在Ubuntu / Win上,Cmd+ Ctrl+单击/在Mac上?)来多选段以加快处理速度。

    现在,这应该“剪切”希望标签显示的轮廓,标签将显示在间隙中。

在这种情况下,我的标签设置为:

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

希望有帮助!


5
这是我能想到的唯一一个完全有效的解决方案。虽然有很多标签,但非常痛苦,我无法想象以这种方式绘制所有地下水位图(每年数千张)。如果将来可以通过样式实现,那就太好了-最好的办法是自定义线条图案和标签重复+偏移量。
米罗

2
简化任务的一些想法:要选择多个线段绘制标签,可以方便地选择“按多边形选择”或“按徒手选择”。另外,另一个方法是创建一个草绘线图层以绘制截取轮廓的线,然后执行“按位置选择”。
Alexandre Neto

7

我在“标签设置”选项卡上使用“缓冲区”选项。(使用标签按钮,而不是图层属性对话框上的旧标签选项。)这并没有抹平轮廓线,正如我想像的那样,但这确实使标签清晰易读。


4
我以前从没想过,但是如果不用为缓冲区分配颜色,而可以选择将其作为“敲除”功能应用到选定的图层上,将会很方便。
Scro 2013年

4
最新版本的QGIS具有透明的缓冲区,因此您可以减少对地图其他部分的影响。
内森·W

1
@MAP剔除会删除其下方的像素。如果可以选择,在这种情况下,您将选择剔除轮廓层。
Scro


1
@MAP-赞助开发人员,或提交功能请求并等待他人的仁慈。:)
Scro 2013年

5

我认为,使用当前QGIS功能可以得到的最接近的结果是对表中使用的颜色使用光晕(或背景)效果,该效果将基于与基础网格相同的高程值和配色方案。当然,这不会考虑山体阴影和地图中光环下方的所有其他内容。随机颜色示例: 标签光晕效果的随机颜色 使用一些代码,可以将其重写为反映网格颜色的函数。

从理论上讲,应该可以使用自定义线条图案和标签重复+偏移量。不幸的是,没有标签偏移设置。

  • 经过一些测试后,不可能强制QGIS严格地将标签放置在精确的间隔中,并且没有其他地方(无论如何+缺少起始偏移量)
  • 无法创建零毫米的自定义线条图案,以使空间具有起始偏移量,例如20线-10间隔-70线-0间隔-因此标签将每隔100mm放置,起始偏移30mm,这意味着标签将位于每10mm孔的中间。

在此处输入图片说明


2

最近遇到相同的问题后,我整理了一个QGIS Python脚本来执行繁重的工作。可以在https://github.com/pjgeng/Contour-Labels上找到包含一些(英国)测试数据,自述文件(指南)和样式表的脚本。

简而言之,脚本使用两个矢量层作为输入-带注释的轮廓层和“引导”层。后者包括在所需标签位置与轮廓相交的折线。

然后,脚本根据轮廓之间的距离和要应用标签的索引轮廓间隔进行计算,将旋转值添加到标签点,最后裁剪原始轮廓层以产生间隙。

最终结果的特写。

如果用户需要在同一区域中以不同的间隔生成等高线图(即指南不变),则该方法特别有效。缺点是脚本完成后无法更改标签位置。为此,用户将不得不调整指导线,并针对原始输入重新运行脚本。我以前在标签周围使用了很多缓冲区来创建中断效果,但是在矢量数据驱动的地图上,这在美学上是令人不快的。

不幸的是,我目前无法添加任何图片来记录或进一步说明该过程。

PS:如果使用存储库中提供的样式层,则用户可能需要“激活”标签菜​​单中“旋转”,“显示标签”和“始终显示”的自定义字段。在某些QGIS安装中,这些是从样式表中自动应用的-我还没有找到引起这种情况的原因。


2

这是针对QGIS轮廓标签掩盖问题的另一种解决方案,其中我利用QGIS的Spatialite功能(当前为QGIS 3.x)以及用于标签放置的几何图形生成器。

这种非常动态的解决方案使我们能够立即更改所有标签文本的大小和标签位置,甚至还可以保留PDF矢量输出!

在此处输入图片说明在此处输入图片说明在此处输入图片说明在此处输入图片说明

为了实现这一点,我们需要以下部分:

  1. “ LINESTRING”或“ MULTILINESTRING”矢量层称为“轮廓”,具有2个字段:“ fid”(Interger64 –主键),“ elev”(字符串)
  2. 一个名为“ scratch_lines”的“ LINESTRING”矢量层(请参见图片中的红线)
  3. 一个无几何图形的表,称为“设置”,用于存储全局轮廓标签的大小(这是一个简单的解决方法,因为QGIS现在无法在SQL查询中使用Project变量):“ fid”(Integer64 –主键),“变量” (字符串),“值”(字符串)

在此处输入图片说明

  1. 具有基于规则的样式的虚拟层,即“ contours_with_labels”:

    • 规则1:“标签” = 1…简单线条,不透明度0%
    • 规则2:ELSE…简单的一行

    • 以及规则1的条件标签文字:

      标签= 1时的情况然后否则升高''结束

    • 与用于文本放置的几何生成器:

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

    • 以及一个用于可变文本大小的Expression String:

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

最后但并非最不重要的一点是虚拟层的SQL查询:

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

而已。

非常感谢所有这些使这一切成为可能的热情人士!


我必须说,我对结果印象深刻。在获得内置选项(如果有)之前,这绝对是最干净的方法。虚拟层再次解救。
Gabriel C.

我的确给我留下了深刻的印象。但是,它可以承受很大的轮廓层吗?
christoph

1

你还记得马丁这个话题吗?我能想到的解决问题的唯一方法是在轮廓层上覆盖修剪的轮廓层,使用它进行标签,并将线条颜色更改为中性,以掩盖标签下的轮廓,希望不要太过分打扰。N.

后来补充说:它可能是值得期待在这个线程太多,第二个答案。也许打破轮廓线可能是一个答案,也许是使用裁剪轮廓的缓冲层?



0

为了使标签更完美,我更改了虚拟层的SQL查询,以尊重与轮廓线平行的刮擦线(请参见下面的解决方案):

旧版 在此处输入图片说明

新版本 在此处输入图片说明

这是虚拟层的新SQL:

------------------------------------------------------------------------
-- 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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.