Переход на альтернативную метку, если первая метка не вписывается в QGIS?

10

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

То, что я хотел бы сделать, это иметь какое-то выражение, которое я могу использовать, чтобы выбрать, какую метку использовать на карте и какие строки включить в таблицу атрибутов. Нечто подобное isLabelledмогло бы учитывать масштаб карты, длину надписи, размер шрифта и т. Д.

Ян Тертон
источник
2
Имейте в виду, что для пользователя карты может возникнуть путаница, когда полигоны одного и того же класса пространственных объектов помечены по-разному, и, кроме того, только некоторые из них отображаются в таблице атрибутов.
таллист
Я имею в виду карту округа Великобритании
Ян Тертон
Как насчет динамического изменения шрифта, чтобы соответствовать? Вы можете взять самое длинное из измерений пространственных объектов, разделить на количество символов в строке метки и либо сделать какую-то математическую операцию со шкалой, либо просто использовать ее для изменения уже установленного размера шрифта ... В качестве альтернативы вы можете использовать эту меру (самая длинная). размерность / длина строки) и, если это слишком длинная метка с идентификатором.
Джесси Макмиллан
в основном меня интересует удобочитаемость, поэтому я не хочу связываться с размером шрифта
Ian Turton
1
Вы можете использовать пользовательское выражение Python, принимающее метку, размер шрифта и масштаб и возвращающее true или false, если оно будет соответствовать. Затем в механизме выражений используйте условие if для переключения меток. Я разработаю для вас ответ позже с примерами.
Джесси Макмиллан

Ответы:

8

Вот несколько приблизительный (но, надеюсь, эффективный) способ сделать это.

Сначала немного математики. Нам нужно выяснить, сколько символов с определенным размером шрифта может содержать функция. Вот что нужно знать / предположения:

  • предполагая метрические единицы (ниже добавлено небольшое изменение, которое может сделать эту работу для нас пешеходами)
  • Размер шрифта является мерой высоты шрифта. Большинство шрифтов примерно в два раза шире, чем они высокие.
  • используя pt для высоты шрифта, 1pt примерно 0.035CM
  • при условии, что ваши посылки примерно прямоугольные / обычные

Чтобы определить, как долго элемент находится на экране / распечатке, мы можем использовать его самое длинное измерение (длину или высоту или просто длину, если ваши надписи только горизонтальные) / масштаб * 100 (чтобы перейти от М к СМ)

Тогда мы можем увидеть, подойдет ли наш лейбл.

Вы можете сделать все это в движке выражений, но пользовательское выражение Python будет более эффективным. Вот учебник о том, как его создать.

Мое собственное выражение:

from qgis.core import *
from qgis.gui import *

@qgsfunction(args='auto', group='Custom')
def labelFits(labelStr, fontPt, scaleM, feature, parent):
    # returns true if a label will fit in the feature at a given
    # font size and scale

    bbox = feature.geometry().boundingBox()

    # for CRS in us foot
    # fontWidth = fontPt * 0.0875

    # for CRS in metric
    # 1pt = 0.035CM
    fontWidth = fontPt * 0.035 * 0.5

    # length of maximum dimension on-screen/print in CM
    labelRoom =  max(bbox.width(),bbox.height()) / scaleM * 100

    # approx length of our label in CM based on font height * 0.5
    labelLen = len(labelStr) * fontWidth

    if labelRoom > labelLen:
        return True
    else:
        return False

Затем просто используйте это выражение в метке:

if(labelFits( "yourAttribute" , 8 , @map_scale ), "yourAttribute",$id)

Вам, конечно, нужно будет подключить любой атрибут, который вы на самом деле используете, и изменить размер шрифта с 8 на тот, который вы используете. Кроме того, поскольку шрифты сильно различаются, вам, возможно, придется немного подправить его, чтобы он выглядел правильно.

Вы также можете использовать это выражение для таких вещей, как изменение цвета в зависимости от того, подходит метка или нет.


Чтобы использовать это выражение вне холста карты (т.е. в метке композитора или в таблице атрибутов), нам нужен способ программно получить масштаб данного элемента карты. Я разместил код для выполнения этого в другом ответе здесь . Метод там дает нам выражение getScale ('имя композитора', 'имя_карты'), чтобы включить его в наше выражение:

if(
    labelFits( "yourAttribute" , 8 , getScale('composername','mapname')),
    "yourAttribute",$id)
Джесси Макмиллан
источник
1
Я тоже думал о чем-то подобном. Особенно если использовать единицы карты и проекцию в метрах. Здесь также могут помочь новые (ish) геометрические операторы, если предположить, что метки центрированы на центроиде. Это будет работать лучше с шрифтом фиксированной ширины (моноширинный), чем с пропорциональным шрифтом (например, где «W» гораздо шире, чем «i»). Вы кое-что здесь делаете, но я подозреваю, что пропорциональные шрифты и кернинг добавят сложности.
Стивен Кей
Вы можете использовать pilf imagefont.getsize (). Это даст вам точную ширину строки, отображаемой выбранным вами шрифтом, но я думаю, что это сильно повлияет на производительность. Грубая математика, описанная выше, намного проще, особенно если на экране сотни этикеток
Джесси Макмиллан,
Единственная незначительная проблема заключается в том, что функция не работает как фильтр в таблицах атрибутов в print composer.
Ян Тертон
Масштаб вашей карты меняется от страницы к странице? Попробуйте вручную ввести масштаб вместо переменной @map_scale. я думаю, что таблица атрибутов не может знать масштаб вашей карты. (Потому что, например, вы можете иметь несколько элементов карты в композиторе в разных масштабах)
Джесси Макмиллан
1
@iant Я разместил ссылку на другое пользовательское выражение, которое программно получит масштаб вашей карты композитора.
Джесси Макмиллан
3

Дублируйте слой, один без символов, и установите различные уровни масштабирования / настройки препятствий для меток для каждого.

Том Чедвин
источник
1

У меня была похожая ситуация с обязательством маркировать каждую дорогу в слое дороги. Мое решение состояло в том, чтобы создать холст большего размера, экспортировать в PDF, а затем распечатать PDF-файл до требуемого размера.

Например, готовый продукт должен был быть A3. На холсте на А3 я не смог уместить все надписи. Поэтому я сделал холст A2, и это позволило увидеть все этикетки. Создайте PDF карту размера А2 и распечатайте ее как A3.

Johanna
источник