Как определить соседние идентификаторы плиток в QGIS?

11

В ходе недавнего учебного курса меня спросили, может ли QGIS автоматически рассчитать номера страниц следующего / предыдущего и выше / ниже для книги карт, созданной с использованием генератора атласа. Мне удалось выработать довольно разумное выражение метки для обычной сетки, если вы знаете ширину и высоту сетки.

Но затем мы начали думать о реалистичных примерах, когда мы не хотим рисовать страницы, которые не содержат интересующую нас область, например, в моем округе:

введите описание изображения здесь

Поэтому во второй половине дня я была игра на питон скрипт для работы из 4 -х соседей я был заинтересован в каждой ячейку сетки и добавлены эти значения в мою сетку (это в значительной степени основывается на Ujaval Ганди учебника ):

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

Это работает просто отлично.

введите описание изображения здесь

Но, честно говоря, создание контрольной точки на севере, а затем проверка всех возможных соседей кажется неправильным. Однако после полудня, потрясшего мой мозг, я не могу придумать лучшего способа определить, кто является северным соседом конкретной ячейки сетки?

В идеале я хотел бы, чтобы что-то достаточно простое поместило в текстовое поле для печати, но я подозреваю, что это слишком много, чтобы просить.

Ян Тертон
источник
Что делать, если с одной стороны нет соседа. Хотите ли вы, чтобы значение закрытой ячейки было в одном направлении, или вы бы оставили пустоту?
Радучжу
Я рад за ноль в этом случае, я могу легко установить метку для отображения только когда не ноль или пусто.
Ян Тертон

Ответы:

3

Если вы не вписываете каждый экстент страницы (из слоя индекса) точно в композитор, а вместо этого имеете перекрывающиеся границы со смежными страницами (как показано на втором снимке экрана), то вы можете использовать метки из слоя индекса, с обратной стороной, которая они будут внутри границы карты.

Если нет совпадений, вы можете воспроизвести технику, которую я успешно использовал в прошлом (по совпадению в E & W Sussex!), В MapInfo, где я написал небольшой скрипт, который генерировал набор из четырех точек для каждой функции индекса , смещение на соседние объекты, с атрибутами как номера листа, так и направления смещения. Затем точечный слой снова использовался для создания меток, причем направление смещения позволяло регулировать ориентацию меток для получения более приятного эффекта.

Я не пробовал этого, но вы можете избежать создания отдельного слоя данных в QGIS за счет использования новой функциональности стилей генератора геометрии, это сделало бы более элегантное и динамичное решение, которого не было в MapInfo!

Энди Харфут
источник
Я действительно должен был подумать только об использовании меток других полигонов! :-) После небольшого эксперимента с генератором геометрии я могу нарисовать ограничивающий прямоугольник, но сложнее построить сетку
Ян Тертон
Я думал о том, как генерировать точки надписи, смещенные относительно соседних многоугольников, а не сеток. Другой вариант заключается в расширении MBR объекта индекса в смежные объекты, чтобы можно было рисовать метки.
Энди Харфут
Только что сыграли, и кажется, что геометрия, сгенерированная стилем генератора геометрии, не помечается, так что это не более элегантное решение, на которое я надеялся.
Энди Харфут
8

На самом деле вы уже выполнили большую часть работы, необходимой для определения листов, которые вы хотите напечатать, используя атлас. Но дело в том, как настроить все вместе, чтобы показывать только те идентификаторы плиток, которые вам нужны. Чтобы продемонстрировать свою идею, я буду использовать в этом примере изображение матрицы высот и векторный файл сетки, как вы можете видеть ниже:

введите описание изображения здесь

Сначала нам нужно показать метку каждой сетки.

В представлении макета я использовал сетку в качестве слоя покрытия в атласе, я создал две карты: карту окна основного вида и карту индекса, которая показывает только сетку, как вы можете видеть ниже:

введите описание изображения здесь

Затем я сделал следующее:

  1. Я настроил масштаб индексной карты, чтобы показать весь экстент сетки, затем я установил масштаб
  2. Я исправил экстент просмотра, чтобы предотвратить панорамирование карты при использовании Preview atlas, и
  3. Я включил, Overviewчтобы увидеть экстент и местоположение карты основного вида, как вы можете видеть ниже:

введите описание изображения здесь

Для карты окна основного вида я установил масштаб для экстента каждого блока сетки, чтобы быть уверенным, что масштаб не изменится, если что-то случится, как вы можете видеть ниже;

введите описание изображения здесь

Используя индексную карту, вы можете легко увидеть идентификатор и местоположение каждой плитки со ссылкой на другую плитку, даже если вы выключите сетку в главном окне карты. Например, следующая карта имеет идентификатор плитки = 14, и вы можете видеть окружающие идентификаторы плитки.

введите описание изображения здесь

Обновление :

Я обновлю свой ответ, потому что я понял, что вы хотите показать индекс номеров страниц для окружающих макетов, а не идентификаторы окружающих макетов.

Чтобы облегчить понимание процесса, я обновлю идентификационные номера на карте индекса, чтобы показать номер страницы макета, как показано ниже:

введите описание изображения здесь

Поскольку идентификаторы, которые у меня есть, начинаются с 0 (ноль), идентификатор первой сетки, показанной на карте индекса, будет начинаться с 3. Поэтому я хочу изменить номер страницы, чтобы начать с 1, вычитая 2 из номера идентификатора в Atlas: 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 страниц нет

  • Up Выражение страницы: [%if((@atlas_pagename <= 6),NULL,'↑ Page Number: ' || (@atlas_pagename -6))%]так как нет страниц до 6 в верхнем направлении

  • Выражение ниже страницы: [%if((@atlas_pagename >= 20), Null, '↓ Page Number: ' || (@atlas_pagename + 6))%]поскольку после 20 в нижнем направлении нет страниц

Некоторые выходные результаты:

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

ahmadhanb
источник
Хотя это полезно, это не отвечает на его вопрос.
Виктор
@Victor Спасибо за ваш комментарий, я обновил свой ответ.
Ахмадханб
это работает в вашем примере (и его), так как стороны раскладки / сетки правильные. Если бы они не были прямыми, это не сработало бы, так как число для сложения или вычитания (6 в вашем примере) варьировалось бы в зависимости от страницы атласа, на которой вы находитесь.
Виктор
2
Я согласен с вами. Если сетка не является регулярной, процесс будет более сложным. Но так как он хочет применить это к регулярной сетке, метод, примененный в моем предложенном решении, будет работать.
Ахмадханб
просто отметив тот факт, если у вас есть еще одна хорошая идея! Тем более что моя сетка не регулярная!
Виктор
2

Это решение будет работать для прямоугольных сеток, и оно автоматическое (должно работать для любого сценария без каких-либо настроек вручную).

Предположим, у вас есть сетка с номерами страниц. Вы можете запустить мой скрипт обработки, выбрав в качестве параметров слой сетки и его поле номера страницы. Сценарий создает четыре поля ( right, left, above, below) в слое сетки и вычисляет соответствующий идентификатор соседней страницы для каждой ячейки сетки. Затем вы можете использовать свои выражения (например, [% if( "left" is not NULL, 'to page' || "left", "" ) %]), чтобы показать метки соседних страниц.

Просто добавьте мой репозиторий ( https://github.com/gacarrillor/QGIS-Resources.git ) из плагина QGIS Resource Sharing и установите скрипт: введите описание изображения здесь

введите описание изображения здесь

Как это работает

Сценарий определяет отношение (справа, слева, сверху или снизу), сравнивая координаты ограничивающих прямоугольников как из текущей ячейки сетки, так и из каждой пересекающейся ячейки. Получается, что для каждого отношения одна из координат отсутствует.

Если это отношение above, отсутствующая координата равна yMin, то есть все остальные 3 координаты из ограничивающего прямоугольника текущей ячейки сетки будут присутствовать в ограничивающем прямоугольнике вышеупомянутой ячейки. Помните , что QGIS ограничивающей коробки определяются в следующем порядке: [xMin, yMin, xMax, yMax].

Для числового примера возьмем прямоугольники со сторонами длины 1. Скажем, ограничивающий прямоугольник текущей ячейки определен как bbox1=[0,0,1,1]. Ограничительная рамка вышеупомянутой ячейки будет определена как bbox2=[0,1,1,2]. Координаты X из bbox1 присутствуют в bbox2, тогда как координаты bbox1 yMinотсутствуют в координатах Y в bbox2.

Мы можем определить наши 4 отношения следующим образом (o: present, #: missing):

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

Как видите, отсутствующий индекс дает нам всю необходимую нам информацию.

Герман Каррильо
источник