Создание сектора освещения в QGIS?

24

Я использую QGIS 2.18. Мне нужно создать секторные огни для навигационных целей на карте.

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

Конечный результат должен выглядеть примерно так: Светлые сектора правильных цветов, цвет которых отмечен как символ в цветовом поле (RGW), и пунктирные линии на расстоянии от 100 м до 1000 м от буя / маяка / маяка.

Скорее всего, он должен быть создан как символ на основе правил, но мне нужен Python?

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

Ниже приведен пример данных шейп-файла для маяка (к сожалению, не приведенного выше), который имеет зеленый сектор между 114 и 154 градусами, белый сектор между 154 и 168 градусами, красный сектор между 168 и 237 градусами, зеленый сектор между 237 и 314 градусами, белый сектор между 314 и 320 градусами, красный сектор между 320 и 337 градусами (по некоторым причинам, 0 не север, а юг):

пример таблицы шейп-файлов

Бенджамин Доннер
источник
1
связанные gis.stackexchange.com/questions/170950/…
Подземье
2
Пожалуйста, не могли бы вы загрузить образец набора данных и отредактировать свой вопрос, уточнив, какого именно результата вы ожидаете? На прикрепленном изображении я вижу только вселенную символов и цветов.
МГРИТЕ
1
Пример данных поможет здесь. У вас есть одна особенность на секторный свет или одна особенность на буй? Здесь может помочь плагин Wedge Buffer, но насколько это просто, зависит от того, как настроены ваши данные.
Стивен Кей
Привет @mgri и Стивен, я добавил пример данных и попытался прояснить вопрос :), спасибо!
Бенджамин Доннер
1
@mgri линии - это не переменные, а линии, которые должны быть статически показаны в виде линий длиной 900 м между светлыми секторами, как на изображении. Проектируемая система отсчета.
Бенджамин Доннер

Ответы:

50

РЕДАКТИРОВАТЬ Я отредактировал ответ для управления конкретными ситуациями (из-за определенных значений углов) и для того, чтобы не отображать пунктирные линии, когда задан круглый угол.


Я предлагаю решение, только возвращаясь к символике и маркировке на основе правил.

Прежде чем начать, я хочу подчеркнуть, что я сосредоточу внимание на объяснении минимальных действий, которые необходимо выполнить для воспроизведения желаемого результата: это означает, что некоторые другие второстепенные параметры (такие как размеры, ширина и т. Д.) Должны быть легко настроены вами для лучшего соответствия вашим потребностям.

Кроме того, это решение работает только в том случае, если вы предполагаете, что 0градус - это север, а не юг (вместо этого, если бы 0юг, было бы достаточно суммировать 180значение каждый раз, когда в формулах, которые имеют дело с углами, например cos(radians(90)), стало бы, становится равным «90» cos(radians(180 + 90))). Я предпочел сделать это только ради более общего решения.


стайлинг

Мы будем отображать точки с помощью a 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 м, и она создается только в том случае, если угол открытия секторного источника света не является круглым (это происходит во избежание того, чтобы линия разорвала целый круг).

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 м, и она создается только в том случае, если угол открытия секторного источника света не является круглым (это происходит во избежание того, чтобы линия разорвала целый круг).

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

Кроме того, нам нужно установить цвет, который хранится в "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

Обратите внимание, что для этого слоя символов я создал две строки: верхняя строка определяет используемый цвет (на самом деле я установил собственное выражение для этого), а нижняя полезна для определения черной рамки (она будет иметь ширина, превышающая ширину верхней линии). Не забудьте также установить Flatкак Cap styleдля обеих линий, чтобы избежать любого наложения цвета.


этикетирование

1) Установка меток

Перейдите к Layer Properties> Labelsи, как обычно, следуйте красным стрелкам:

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

а затем введите это выражение:

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

Мы только что определили правило цвета, используя значение, сохраненное в "VARIS"поле.

2) Настройка размещения ярлыков

Выберите Placementопцию в Labelsменю и выберите 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 (он должен иметь то же имя используемого вами шейп- файла ).

МГРИ
источник
3
Выглядит великолепно, действительно показывает мощь генератора геометрии. Это медленно, чтобы сделать?
HeikkiVesanto
2
@Vesanto Я проверил его в одной точке, имеющей шесть объектов (т.е. шесть секторных источников света), и он рендерился мгновенно. Я думаю, что это должно быть быстрым и при работе с сотнями функций, потому что нет вызова провайдерам или что-то в этом роде, а только пара математических операций и геометрий, а также Well Know Text.
Мгри
2
Подобные вопросы / ответы действительно показывают, насколько универсальной может быть QGIS!
Джозеф
1
@mgri Вы - Мастер, фантастически хорошее решение и отличное объяснение, включающее много работы, СПАСИБО!
Бенджамин Доннер
1
@mgri гора в этом регионе должна быть названа в честь тебя, спасибо !! Я проверил немного, и никаких проблем с добавленными решениями не было найдено :)!
Бенджамин Доннер