Більше

Як створити динамічні лінійні лідери?


Я намагаюся створити динамічні лінії лідерів, використовуючи подання PostGIS на додаток до інструменту QGIS „Move Label“.

СТВОРИТИ ПЕРЕГЛЯНУТЬ рядок_редактора як ВИБЕРИТИ gid, ST_MakeLine (geom, ST_SetSRID (ST_MakePoint (xcord_label, ycord_label), SRID)) :: geometry (linestring, SRID) AS geom FROM point WHERE xcord_label NOT NULL;

Це чудово працює для всіх етикетокДЕ ST_X (geom) але створює неправильні лінії лідерів для етикетокДЕ ST_X (geom)> xcord_label.

Хтось знає, як правильно розмістити лінії лідерів для етикетокДЕ ST_X (geom)> xcord_label? Чи є спосіб посилатися на координату xmax міток?


Ви можете використовувати специфікатор розміщення квадранту QGIS, визначений за азимутом лінії, щоб поставити кращу мітку. Квадрант визначає 8 позицій навколо точки:

[0 = Вгорі зліва | 1 = вгорі | 2 = вгорі праворуч | 3 = Лівий | 4 = Понад | 5 = праворуч | 6 = Внизу зліва | 7 = Внизу | 8 = Знизу праворуч]

Ось приклад навколо острова Нулл, створення таблиці та двох подань.

СТВОРИТИ точки ТАБЛИЦІ (gid serial PRIMARY KEY, геометрична геометрія (Point, 4326), геометрія label_geom (Point, 4326), текст мітки); ВСТАВИТИ У точки (geom, label_geom, label) ВИБЕРИТЬ початок, pt, круглий (градуси (ST_Azimuth (початок, pt))) || 'градуси' FROM (SELECT ST_SetSRID (ST_MakePoint (0, 0), 4326) AS origin, ST_SetSRID (ST_MakePoint (cos (radians (x)), sin (radians (x))), 4326) AS pt FROM generated_series (0, 350, 15) AS x) AS f; СТВОРИТИ АБО ЗАМІНИТИ ПЕРЕГЛЯНУТИ точки_мітки ЯК ВИБЕРИТИ gid, label_geom ЯК geom, ВИПАДК, КОЛИ ST_Azimuth (geom, label_geom) ISNULL THEN 2 - за замовчуванням, якщо азимут неможливо визначити WHEN градусів (ST_Azimuth (geom, label_geom)) <22,5 THEN 1 - Над WHEN градусів (ST_Azimuth (geom, label_geom)) <67,5 THEN 2 - вгорі праворуч WHEN градусів (ST_Azimuth (geom, label_geom)) <112,5 THEN 5 - право КОЛИ градусів (ST_Azimuth (geom, label_geom)) <157,5 THEN 8 - Внизу праворуч КОЛИ градуси (ST_Azimuth (geom, label_geom)) <202,5 ​​THEN 7 - Нижче WHEN градусів (ST_Azimuth (geom, label_geom)) <247,5 THEN 6 - Нижче зліва WHEN градуси (ST_Azimuth (geom, label_geom)) <292,5 THEN 3 - ліворуч КОЛИ градуси (ST_Azimuth (geom, label_geom)) <337,5 THEN 0 - зверху ліворуч ІНШЕ 1 -> = 337,5 Над END AS AS квадрант, мітка FROM points; СТВОРИТИ АБО ЗАМІНИТИ ПЕРЕГЛЯНУТИ лінію_назви ЯК ВИБЕРИТИ gid, ST_MakeLine (geom, label_geom) :: geometry (LineString, 4326) ЯК geom, мітка FROM points;

Потім у QGIS додайте:

  • балів-геом
  • лідер_лідеру-геом- первинний ключ повинен бутиgid
  • мітки_точок-геом- первинний ключ повинен бутиgid

Тепер налаштуйте властивості шару длямітки_точок:

  • Змініть стиль, щоб точка не була намальована, наприклад, змініть розмір на 0,0
  • Позначте цей шар позначкоюетикетціта змініть розміщення на «Зсув від точки», змінивши «Квадрант», використовуючи поле атрибутаквадрант

Бінго!

Зверніть увагу, що для цього потрібен дещо інший підхідгеографіятипи, оскільки ST_Azimuth поводиться по-різному.


Оновлення: При додаванні нових балів добалівшар,геомполе оновлюється, як зазвичай, алеlabel_geomне. Щоб заповнити значення за замовчуваннямlabel_geomз новими точками потрібно створити тригер. Але якщо використовується тригерна функція, токвадрантспецифікатор може зберігатися вбалівтаблиці тамітки_точокподання можна ігнорувати:

Наприклад, давайте почнемо знову з дещо іншого прикладу з однією таблицею та одним видом:

- краплинний стіл точки КАСКАД; СТВОРИТИ точки ТАБЛИЦІ (gid serial ПЕРВИННИЙ КЛЮЧ, геометрія геометрії (Point, 4326), геометрія label_geom (Point, 4326), ціле число квадранта, текст мітки); СТВОРИТИ ФУНКЦІЮ label_geom_tg_fn () RETURNS тригер як $ BODY $ DECLARE азимут float8; BEGIN - Встановити за замовчуванням label_geom IF NEW.label_geom ISNULL THEN NEW.label_geom: = NEW.geom; END IF; - Визначити азимут квадранта: = градуси (ST_Azimuth (NEW.geom, NEW.label_geom)); НОВИЙ.квадрант: = СПРАВА, КОЛИ азимут НІЩЕ ТОГО 2 - азимут визначити неможливо, тому поставте вгорі праворуч КОЛИ азимут <22,5 ТОГО 1 - вгорі КОЛИ азимут <67,5 ТОГО 2 - вгорі праворуч КОЛИ азимут <112,5 ТОГО 5 - право КОЛИ азимут <157,5 ТО 8 - знизу праворуч КОЛИ азимут <202,5 ​​ТО 7 - нижче КОГДА азимут <247,5 ТО 6 - знизу ліворуч КОЛИ азимут <292,5 ТО 3 - ліво КОЛИ азимут <337,5 ТО 0 - зверху ліво ІНШЕ 1 END; -> = 337,5 Вище ВЕРНУТИ НОВЕ; END; $ BODY $ LANGUAGE plpgsql; СТВОРИТИ TRIGGER label_geom_tg ПЕРЕД ВСТАВЛЕННЯМ або ОНОВЛЕННЯМ по точках ДЛЯ КОЖНОЇ РЯДОВОЇ ВИКОНАВЧОЇ ПРОЦЕДУРИ label_geom_tg_fn ();

З першого прикладу повторітьВСТАВИТИ В балиіСТВОРИТИ АБО ЗАМІНИТИ ПЕРЕГЛЯНтвердження, оскільки вони не потребують модифікації. Але ігноруйтелідер_лідерувид.

Потім у QGIS додайте:

  • балів-геом
  • балів-label_geom
  • лідер_лідеру-геом- первинний ключ повинен бутиgid

Тепер налаштуйте властивості шару длябалівзlabel_geomяк це зробив перший приклад длямітки_точок.квадрантспецифікатор буде автоматично модифікований для нових та переміщених точок, але ви помітите ці зміни лише кожного разу, коли зберігаєте свої зміни.


гаразд ... як це в одиницях карт, це повинно бути досить прямо, в межах обмежень. Ви вже знаєте висоту ярлика. Якби це було в балах, це залежало б від масштабу.

Це передбачає фіксований розмір етикетки, тому наскільки це добре працює, залежить від того, наскільки рівномірними є ваші етикетки, і від того, чи використовуєте ви пропорційний шрифт чи фіксовану ширину (фіксовану ширину простіше - помножте довжину етикетки на розмір етикетки на отримати ширину етикетки).

На жаль, це не відповідає на ваше запитання про те, як насправді знайти межі етикетки як надано.

у вас є 4 справи (ПН, Пн, Пд, Пд).

я припускаю, що ваша таблиця виглядає так (вибачення, деякі назви полів різні)

СТВОРИТИ точки ТАБЛИЦІ (uniq int ПЕРВИННИЙ КЛЮЧ, геометрична геометрія (Point, 27700), label_x int, label_y int, мітка символу мітки (100)); ALTER TABLE точки ВЛАСНИК користувачеві; НАДАЙТЕ ВСЕ НА ТАБЛИЦІ бали користувачеві; НАДАЙТЕ ВИБІР ТАБЛИЧНИХ балів ДО ВСІХ

Далі додайте 4 точки (усі однакові), але з мітками в 4 квадрантах, щоб представити 4 основні випадки використання

вставити в значення балів (1, ST_SetSRID (ST_Point (1000,1000), 27700), 750,750, '123'); вставити в значення балів (2, ST_SetSRID (ST_Point (1000,1000), 27700), 1250,1250, '456') вставити в значення балів (3, ST_SetSRID (ST_Point (1000,1000), 27700), 750,1250, '456') вставити в значення балів (4, ST_SetSRID (ST_Point (1000,1000), 27700), 1250,750, '789')

Я використовував CRS 27700 (0,0 внизу ліворуч, одиниці карти в м). Я припустив, що ширина мітки 50, висота 30 одиниць карти.

- Сценарій використання SW СТВОРИТИ АБО ЗАМІНИТИ ПЕРЕГЛЯД Lead_line_sw ЯК ВИБЕРИТИ uniq, ST_MakeLine (geom, ST_SetSRID (ST_MakePoint (label_x + 50, label_y + 30), 27700)) :: geometry (linestring, 27700) ЯК geom ВІД точок, де label_x НЕ NULL І label_y <= ST_Y (geom) та label_x <= ST_X (geom); - Приклад використання SE СТВОРИТИ АБО ЗАМІНИТИ ПЕРЕГЛЯД Lead_line_se ЯК ВИБРАТИ uniq, ST_MakeLine (geom, ST_SetSRID (ST_MakePoint (label_x, label_y-30), 27700)) :: geometry (linestring, 27700) ЯК geom ВІД пунктів, де label_x НЕ НУЛЬНИЙ І label_y <= ST_Y (geom) та label_x> ST_X (geom); - Не використовуйте випадок СТВОРИТИ АБО ЗАМІНИТИ ПЕРЕГЛЯНУТЬ leader_line_ne ЯК ВИБЕРИТИ uniq, ST_MakeLine (geom, ST_SetSRID (ST_MakePoint (label_x, label_y), 27700)) :: geometry (linestring, 27700) ЯК geom ВІД точок, ДЕ label_x НЕ НУЛЬНИЙ І label_y> ST_Y (geom) та label_x> ST_X (geom); - Приклад використання NW СТВОРИТИ АБО ЗАМІНИТИ ПЕРЕГЛЯД Lead_line_nw2 AS SELECT uniq, ST_MakeLine (geom, ST_SetSRID (ST_MakePoint (label_x + 50, label_y), 27700)) :: geometry (linestring, 27700) ЯК geom ВІД точок, де label_x НЕ НУЛЬНИЙ І label_y> ST_Y (geom) та label_x <= ST_X (geom);

Аффінні перетворення

Інша можливість - скоротити всі провідні лінії, скажімо, на 80%.

  • Ви можете використовувати ST_Translate (geom, -ST_X (geom), - ST_Y (geom)), щоб перемістити рядок до початку, щоб отримати geom_o
  • використовуйте ST_Scale (geom_o, 0.8,0.8), щоб отримати geom_o_scaled
  • потім перекладіть за допомогою ST_Translate (geom_o_scaled, ST_X (geom), ST_Y (geom)) назад у вихідне положення.

Це може працювати краще, хоча я ще не пробував.