在QGIS中创建扇形灯?


24

我正在使用QGIS 2.18。我需要在地图上创建用于导航的扇形灯。

我将轻型部门数据作为形状文件中的becon_id,开始程度,结束程度和颜色的字段,其中需要在地图上显示500多个浮标,信标和灯塔。对于每个信标,可以有很多行,每行描述一个光扇区(例如白色扇区)

最终结果应如下所示:正确颜色的光扇区,在色域(RGW)中标记为字符的颜色,以及从浮标/信标/灯塔到100m至1000m的虚线。

这很可能应该创建为基于规则的符号,但是我猜需要一些python吗?

在此处输入图片说明

以下是一个灯塔的shapefile数据示例(不幸的是,上面没有),该灯塔的绿色扇区在114至154度之间,白色扇区在154至168度之间,红色扇区在168至237度之间,绿色介于237至314度之间的扇形,白色的介于314至320度之间的扇形,红色的介于320至337度之间的扇形(由于某种原因,0不是北而是南):

shapefile表示例



2
请,您可以上传样本数据集并通过详细说明期望的结果来编辑问题吗?在所附的图像中,我仅看到符号和颜色的范围。
mgri

1
示例数据将在这里有所帮助。每个扇形灯有一个功能,还是每个浮标有一个功能?Wedge Buffer插件在这里可能会有所帮助,但这是否简单取决于您的数据设置方式。
史蒂文·凯

@mgri和Steven,您好,我添加了示例数据,并试图使问题更清晰:),谢谢!
本杰明·唐纳

1
@mgri线不是变量,而是应该静态显示为光扇之间的900m长线的线(如图像中所示)。投影参考系统。
本杰明·唐纳

Answers:


50

编辑我编辑了用于管理特定情况(由于特定角度值)和在定义圆角时不显示虚线的答案。


我仅通过重复基于规则的符号体系和标签来提出一种解决方案。

在开始之前,我想强调一下,我将把注意力集中在对再现所需结果的最小操作的解释上:这意味着您还可以轻松调整一些其他次要参数(例如大小,宽度等)为了更好地满足您的需求。

此外,该解决方案仅在假设0度数为北而不是南的情况下才有效(如果0为南,则180每次在处理角度的公式中出现“ 90”(例如cos(radians(90))变为cos(radians(180 + 90)))时,将一个值相加就足够了)。我更愿意这样做只是为了给出更通用的解决方案。


造型

我们将Single symbol通过重复一个Simple Marker和三个Geometry generator符号层来使用和渲染点:

在此处输入图片说明

在进一步的说明中,我将遵循上图中符号的相同顺序。

1)简单标记

我选择了一个黑星的默认符号(这是本教程中比较容易的部分),其大小为3毫米,宽度为0.4毫米。

2)1号几何生成器

添加一个新的符号层并选择Geometry generator类型:

在此处输入图片说明

将此表达式插入Expression字段:

CASE
WHEN abs( "ALKUKULMA" - "LOPPUKULMA") < 360
THEN
make_line(
 $geometry,
 make_point(
  $x + 1000*cos(radians(90 - "ALKUKULMA")),
  $y + 1000*sin(radians(90 - "ALKUKULMA"))
  )
)
END

我们刚刚定义了第一条线,该线指向光扇区的起点。这条线长1000 m,仅在扇形灯的开度角不是圆角时才创建(这是为了避免该线会破坏整个圆)。

3)2号几何生成器

与上面相同,但是在此步骤中,您需要使用以下表达式:

CASE
WHEN abs( "ALKUKULMA" - "LOPPUKULMA") < 360
THEN
make_line(
 $geometry,
 make_point(
  $x + 1000*cos(radians(90 - "LOPPUKULMA")),
  $y + 1000*sin(radians(90 - "LOPPUKULMA"))
  )
)
END

我们刚刚定义了第一条线,该线指向光扇区的结束点。这条线长1000 m,仅在扇形灯的开度角不是圆角时才创建(这是为了避免该线会破坏整个圆)。

4)3号几何发生器

将此表达式插入Expression字段:

CASE

WHEN abs("ALKUKULMA" - "LOPPUKULMA") <= 180 AND "ALKUKULMA" >= "LOPPUKULMA"
THEN
difference(
 boundary(
  buffer(
   $geometry, 900)
   ),
  make_polygon(
   geom_from_wkt(
    geom_to_wkt(
     make_line(
      $geometry,
      make_point($x + 2000*cos(radians(90 - "ALKUKULMA" )), $y + 2000*sin(radians((90 - "ALKUKULMA" )))),
      make_point($x + 2000*cos(radians(90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )), $y + 2000*sin(radians((90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )))),
      make_point($x + 2000*cos(radians(90 - "LOPPUKULMA")), $y + 2000*sin(radians((90 - "LOPPUKULMA")))),
      $geometry)
   )  
  )
 )
)

WHEN abs("ALKUKULMA" - "LOPPUKULMA") <= 180 AND "ALKUKULMA" <= "LOPPUKULMA"
THEN
intersection(
 boundary(
  buffer(
   $geometry, 900)
   ),
  make_polygon(
   geom_from_wkt(
    geom_to_wkt(
     make_line(
      $geometry,
      make_point($x + 2000*cos(radians(90 - "ALKUKULMA" )), $y + 2000*sin(radians((90 - "ALKUKULMA" )))),
      make_point($x + 2000*cos(radians(90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )), $y + 2000*sin(radians((90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )))),
      make_point($x + 2000*cos(radians(90 - "LOPPUKULMA")), $y + 2000*sin(radians((90 - "LOPPUKULMA")))),
      $geometry)
   )  
  )
 )
)

WHEN abs("ALKUKULMA" - "LOPPUKULMA") > 180 AND "ALKUKULMA" >= "LOPPUKULMA"
THEN
intersection(
 boundary(
  buffer(
   $geometry, 900)
   ),
  make_polygon(
   geom_from_wkt(
    geom_to_wkt(
     make_line(
      $geometry,
      make_point($x + 2000*cos(radians(90 - "ALKUKULMA" )), $y + 2000*sin(radians((90 - "ALKUKULMA" )))),
      make_point($x - 2000*cos(radians(90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )), $y - 2000*sin(radians((90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )))),
      make_point($x + 2000*cos(radians(90 - "LOPPUKULMA")), $y + 2000*sin(radians((90 - "LOPPUKULMA")))),
      $geometry)
   )  
  )
 )
)

WHEN abs("ALKUKULMA" - "LOPPUKULMA") > 180 AND "ALKUKULMA" <= "LOPPUKULMA"
THEN
difference(
 boundary(
  buffer(
   $geometry, 900)
   ),
  make_polygon(
   geom_from_wkt(
    geom_to_wkt(
     make_line(
      $geometry,
      make_point($x + 2000*cos(radians(90 - "ALKUKULMA" )), $y + 2000*sin(radians((90 - "ALKUKULMA" )))),
      make_point($x - 2000*cos(radians(90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )), $y - 2000*sin(radians((90 - ("LOPPUKULMA" + "ALKUKULMA")/2 )))),
      make_point($x + 2000*cos(radians(90 - "LOPPUKULMA")), $y + 2000*sin(radians((90 - "LOPPUKULMA")))),
      $geometry)
   )  
  )
 )
)


END

我们刚刚定义了光扇形的起点和终点之间的圆弧(请注意,这2000是一个任意值,因为我正试图创建一个与半径为900 m的圆的边界相交的多边形)。

此外,我们需要设置存储在"VARIS"字段中的颜色。为此,我们需要使用自定义表达式来指定它。请按照下图中的箭头:

在此处输入图片说明

然后在单击Edit...按钮后键入以下表达式:

CASE
WHEN  "VARIS" = 'vi' THEN color_rgb(51,160,44)
WHEN "VARIS" = 'v' THEN color_rgb(255,255,255)
WHEN "VARIS" = 'p' THEN color_rgb(227,26,28)
END

请注意,对于该符号层,我创建了两行:上一行定义了要使用的颜色(实际上,我为此设置了自定义表达式),而下一行则用于定义黑色边框(它将具有大于上一行的宽度)。记住还设置FlatCap style两条线路用于避免任何颜色重叠。


贴标

1)设置标签

转到Layer Properties> Labels,然后像往常一样遵循红色箭头:

在此处输入图片说明

然后键入此表达式:

CASE
WHEN "VARIS" = 'vi' THEN 'G'
WHEN "VARIS" = 'v' THEN 'W'
WHEN "VARIS" = 'p' THEN 'R'
END

我们刚刚使用存储在"VARIS"字段中的值定义了颜色规则。

2)设置标签的位置

PlacementLabels菜单中选择选项,然后选择Offset from point

然后,参考下图:

在此处输入图片说明

按照红色箭头并输入以下表达式:

CASE
WHEN "ALKUKULMA" > "LOPPUKULMA"
THEN
concat(
 -1000*cos(radians(90 - ("ALKUKULMA" + "LOPPUKULMA")/2)),
  ',',
  1000*sin(radians(90 - ("ALKUKULMA" + "LOPPUKULMA")/2))
)
WHEN "ALKUKULMA" <= "LOPPUKULMA"
THEN
concat(
 1000*cos(radians(90 - ("ALKUKULMA" + "LOPPUKULMA")/2)),
  ',',
  -1000*sin(radians(90 - ("ALKUKULMA" + "LOPPUKULMA")/2))
)
END

然后,跟随绿色箭头并键入此表达式:

CASE
WHEN "ALKUKULMA" >= "LOPPUKULMA"
THEN
180-(("ALKUKULMA" + "LOPPUKULMA")/2)
WHEN "ALKUKULMA" < "LOPPUKULMA"
THEN
- (("ALKUKULMA" + "LOPPUKULMA")/2)
END

最后结果

如果正确执行了先前的任务,则应该能够得到以下结果:

在此处输入图片说明

奖金

由于次要参数太多,无法完全涵盖在此答案中,因此我在此处附加了样式:您可以使用任何文本编辑器打开此代码,并将其另存为QGIS图层样式文件(即带有.qml扩展名)。

上面的样式是使用QGIS 2.18.4创建的(必须与您使用的shapefile具有相同的名称)。


3
看起来很棒,真的向您展示了几何生成器的功能。渲染速度慢吗?
HeikkiVesanto

2
@Vesanto我在具有六个功能(即六个扇形灯)的一点上对其进行了测试,并立即对其进行了渲染。我认为在处理数百种功能时也应该很快,因为不需要调用提供程序或类似功能,而只需使用几次数学运算和几何(如“熟知的文本”)即可。
mgri

2
诸如此类的问题/答案确实表明了QGIS的通用性!
约瑟夫

1
@mgri,您是大师,一个奇妙的解决方案,并且涉及很多工作,但非常出色的解释,谢谢!!
本杰明·唐纳

1
@mgri这个地区的一座山应该以你命名,谢谢!我测试了一下,没有发现您添加的解决方案有问题:)!
本杰明·唐纳
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.