如何确定QGIS中的相邻图块ID?


11

在最近的培训课程中,有人问我QGIS是否可以自动计算使用地图集生成器创建的地图册的下一页/上一页以及上一页/下一页。如果您知道网格的宽度和高度,那么我设法为常规网格制定了一个相当合理的标签表达式。

但是随后我们开始考虑一些现实的示例,在这些示例中我们不想绘制不包含我们感兴趣的地区的页面,例如我的家乡之一:

在此处输入图片说明

因此,今天下午我在一个python脚本上玩耍,计算出每个网格单元我感兴趣的4个邻居,并将这些值添加到我的网格中(这很大程度上基于Ujaval Gandhi的教程):

for f in feature_dict.values():
    print 'Working on %s' % f[_NAME_FIELD]
    geom = f.geometry()
    # Find all features that intersect the bounding box of the current feature.
    # We use spatial index to find the features intersecting the bounding box
    # of the current feature. This will narrow down the features that we need
    # to check neighboring features.
    intersecting_ids = index.intersects(geom.boundingBox())
    # Initalize neighbors list and sum
    neighbors = []
    neighbors_sum = 0
    for intersecting_id in intersecting_ids:
        # Look up the feature from the dictionary
        intersecting_f = feature_dict[intersecting_id]
        int_geom = intersecting_f.geometry()
        centroid = geom.centroid()
        height = geom.boundingBox().height()
        width = geom.boundingBox().width()
        # For our purpose we consider a feature as 'neighbor' if it touches or
        # intersects a feature. We use the 'disjoint' predicate to satisfy
        # these conditions. So if a feature is not disjoint, it is a neighbor.
        if (f != intersecting_f and
            not int_geom.disjoint(geom)):
            above_point = QgsGeometry.fromPoint(QgsPoint(centroid.asPoint().x(),
               centroid.asPoint().y()+height))
            below_point = QgsGeometry.fromPoint(QgsPoint(centroid.asPoint().x(),
               centroid.asPoint().y()-height))
            left_point = QgsGeometry.fromPoint(QgsPoint(centroid.asPoint().x()-width,
               centroid.asPoint().y()))
            right_point = QgsGeometry.fromPoint(QgsPoint(centroid.asPoint().x()+width,
               centroid.asPoint().y()))
            above = int_geom.contains(above_point)   
            below = int_geom.contains(below_point)   
            left = int_geom.contains(left_point)
            right = int_geom.contains(right_point)
            if above:
                print "setting %d as above %d"%(intersecting_f['id'],f['id'])
                f['above']=intersecting_f['id']

            if below:
                print "setting %d as below %d"%(intersecting_f['id'],f['id'])
                f['below']=intersecting_f['id']

            if left:
                print "setting %d as left of %d"%(intersecting_f['id'],f['id'])
                f['left']=intersecting_f['id']

            if right:
                print "setting %d as right of %d"%(intersecting_f['id'],f['id'])
                f['right']=intersecting_f['id']

    # Update the layer with new attribute values.
    layer.updateFeature(f)

layer.commitChanges()

这很好。

在此处输入图片说明

但老实说,整个过程要建立一个指向北方的测试点,然后测试所有可能的邻居,似乎是错误的。但是,经过一个下午的搏动,我无法想到一种更好的方法来确定特定网格单元的北部邻居是什么?

理想情况下,我想要足够简单的东西来放入打印作曲家文本框,但是我怀疑这要求太多了。


如果一侧没有邻居怎么办。您是否要在一个方向上使用closeset单元格的值,还是要留一个空白?
radouxju

在那种情况下,我很高兴为空,我可以轻松地将标签设置为仅在不为空或为空时显示。
伊恩·特顿

Answers:


3

如果您不是将每个页面范围(来自索引层)完全适合于作曲家,而是与相邻页面具有重叠的边框(如第二个屏幕截图所示),则可以使用索引层中的标签,缺点是它们将位于地图边框内。

如果没有任何重叠,那么您可以在MapInfo中复制我过去成功使用的技术(恰好在E&W Sussex上!),在这里我编写了一个小脚本,为每个索引特征生成一组四个点,偏移到相邻要素中,同时具有图纸编号和偏移方向的属性。然后使用点层再次生成标签,其偏移方向允许调整标签的方向以获得更好的效果。

我没有尝试过,但是您可以避免通过使用新的几何体生成器样式功能在QGIS中生成单独的数据层,这将为MapInfo带来无法实现的更优雅,更动态的解决方案!


我真的应该考虑只使用其他多边形的标签!:-)在使用“几何体生成器”进行了快速实验之后,我可以绘制一个边界框,但是要构建网格却比较困难
伊恩·特顿

我一直在考虑生成偏移到相邻多边形而不是网格的标签点的路线。另一个选择是将索引要素的MBR扩展到相邻要素中,以允许绘制标签。
安迪·哈富特

刚玩了一次,看来几何生成器样式生成的几何没有贴标签,所以不是我所希望的更优雅的解决方案。
安迪·哈富特

8

实际上,您已经完成了确定要使用图集打印的图块所需的大部分工作。但关键是如何调整所有内容以仅显示所需的图块ID。为了说明我的想法,在本示例中,我将使用DEM图像和网格矢量文件,如下所示:

在此处输入图片说明

首先,我们需要显示每个网格的标签。

在布局视图中,我将栅格用作地图集的覆盖层,创建了两个地图:主视图窗口地图和仅显示栅格的索引地图,如下所示:

在此处输入图片说明

然后,我执行以下操作:

  1. 我调整了索引图的比例以显示整个网格范围,然后固定比例
  2. 我修复了视图范围,以防止在使用时平移地图 Preview atlas,以及
  3. 我启用Overview可以查看主视图地图的范围和位置,如下所示:

在此处输入图片说明

对于主视图窗口贴图,我将比例尺固定在每个网格块的范围内,以确保在发生任何事情时都不会更改比例尺,如下所示;

在此处输入图片说明

使用索引贴图,即使从主视图贴图窗口中关闭网格,也可以轻松参考其他贴图查看每个贴图的ID和位置。例如,以下地图的图块ID = 14,您可以看到周围的图块ID。

在此处输入图片说明

更新

我将更新我的答案,因为我意识到您想显示周围布局的页码索引,而不是周围布局的ID。

为了简化对过程的了解,我将更新索引图中的ID号以显示布局页号,如下所示:

在此处输入图片说明

由于我的ID从0(零)开始,因此索引图上显示的第一个网格的ID将从3开始。因此,我想通过从Atlas的ID号中减去2来将页码从1开始更改:Page number: ID -2,那么我将使用当前页码作为表达式中的引用来为当前页,上一页,下一页,上一页和下一页创建标签,如下所示:

在此处输入图片说明

  • 当前页面在标签文本框中具有以下表达式: Current Page Number: [%@atlas_pagename%]

  • 上一页的表达:[%if((@atlas_pagename = 1), Null, '↑ Page Number: ' || (@atlas_pagename - 1))%]由于1之前没有页面

  • 下一页页面表达式:[%if( (@atlas_pagename = 25), Null, '↓ Page Number: ' || (@atlas_pagename + 1))%]由于25之后没有页面

  • 向上的页面表达:[%if((@atlas_pagename <= 6),NULL,'↑ Page Number: ' || (@atlas_pagename -6))%]由于在上方6之前没有页面

  • 在页面表达式下方:[%if((@atlas_pagename >= 20), Null, '↓ Page Number: ' || (@atlas_pagename + 6))%]由于20以后的较低页面没有页面

一些输出结果:

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明


尽管有用,但这不能回答他的问题。
维克多

@Victor感谢您的评论,我更新了答案。
ahmadhanb '16

这在您的示例(和他的示例)中有效,因为键映射/网格的侧面是规则的。如果它们不是直的,则将不起作用,因为要添加或减去的数字(在您的示例中为6)将根据您所在的地图集页面而有所不同。
维克多

2
我同意你的看法。如果网格不规则,则过程将更加复杂。但是,由于他想将其应用于常规网格,因此在我建议的解决方案中应用的方法将起作用。
ahmadhanb '16

仅注意事实,以防万一您有另一个好主意!特别是因为我的网格不规则!
维克多

2

该解决方案适用于矩形网格,并且是自动的(无需手动调整即可适用于任何情况)。

假设您有一个带有页码的网格。您可以运行“ 处理”脚本,选择网格图层及其页码字段作为参数。该脚本right, left, above, below在网格层中创建四个字段(),并为每个网格单元计算相应的邻居页面ID。然后,您可以使用表达式(例如[% if( "left" is not NULL, 'to page' || "left", "" ) %])显示邻居页面标签。

只需从QGIS资源共享插件添加我的存储库(https://github.com/gacarrillor/QGIS-Resources.git)并安装脚本: 在此处输入图片说明

在此处输入图片说明

这个怎么运作

该脚本通过比较当前网格单元格和每个相交单元格的边界框坐标来确定关系(右,左,上或下)。事实证明,对于每个关系,缺少一个坐标。

如果该关系为above,则丢失的坐标为yMin,即当前网格单元边界框内的所有其他3个坐标将出现在上述单元的边界框中。请记住,QGIS边界框是按以下顺序定义的:[xMin, yMin, xMax, yMax]

对于一个数字示例,我们以边长为1的矩形为例。假设当前单元格的边界框定义为bbox1=[0,0,1,1]。上面单元格的边界框将定义为bbox2=[0,1,1,2]。bbox2中存在来自bbox1的X坐标,而bbox2的yMinY坐标中缺少bbox1。

我们可以通过以下方式定义4个关系(o:存在,#:缺失):

right: [#,o,o,o]
above: [o,#,o,o]
left:  [o,o,#,o]
below: [o,o,o,#]

如您所见,缺少索引可为我们提供所需的所有信息。

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.