28. 3D (тривимірний)

28.1. Тривимірні геометрії

Поки що ми працювали з двовимірними геометріями, що мають лише координати X та Y. Але PostGIS підтримує додаткові виміри для всіх типів геометрій — вимір «Z» для додавання інформації про висоту та вимір «M» для додаткової інформації (зазвичай це час, кілометраж дороги або відстань за течією) для кожної координати.

Для тривимірних (3D) та чотиривимірних (4D) геометрій додаткові виміри додаються як додаткові координати для кожної вершини геометрії, а тип геометрії розширюється, щоб вказати, як інтерпретувати ці додаткові виміри. Додавання додаткових вимірів призводить до появи трьох нових можливих типів геометрії для кожного примітиву геометрії:

  • До типу Point (двовимірний тип) додаються типи PointZ, PointM та PointZM.

  • До типу Linestring (двовимірний тип) додаються типи LinestringZ, LinestringM та LinestringZM.

  • До типу Polygon (двовимірний тип) додаються типи PolygonZ, PolygonM та PolygonZM.

  • І так далі.

Для представлення у форматі well-known text (:term:WKT) формат для багатовимірних геометрій визначений у специфікації ISO SQL/MM. Інформація про додаткові виміри просто додається до текстового рядка після назви типу, а додаткові координати — після координат X/Y. Наприклад:

  • POINT ZM (1 2 3 4)

  • LINESTRING M (1 1 0, 1 2 0, 1 3 1, 2 2 0)

  • POLYGON Z ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0))

Функція ST_AsText() повертатиме наведені вище подання при роботі з тривимірними (3D) та чотиривимірними (4D) геометріями.

Для подання у форматі well-known binary (:term:WKB) формат для багатовимірних геометрій визначено у специфікації ISO SQL/MM. BNF-форма цього формату доступна за посиланням: https://git.osgeo.org/gitea/postgis/postgis/src/branch/master/doc/bnf-wkb.txt.

Окрім багатовимірних варіантів стандартних типів, PostGIS включає кілька нових типів, які мають сенс у тривимірному просторі:

  • Тип TIN дозволяє моделювати трикутні сітки у вигляді рядків у вашій базі даних.

  • Тип POLYHEDRALSURFACE дозволяє моделювати об’ємні об’єкти у вашій базі даних.

Оскільки обидва ці типи призначені для моделювання тривимірних об’єктів, має сенс використовувати лише варіанти з виміром Z. Прикладом POLYHEDRALSURFACE Z може бути куб зі стороною 1 одиниця:

POLYHEDRALSURFACE Z (
  ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),
  ((0 0 0, 0 1 0, 0 1 1, 0 0 1, 0 0 0)),
  ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)),
  ((1 1 1, 1 0 1, 0 0 1, 0 1 1, 1 1 1)),
  ((1 1 1, 1 0 1, 1 0 0, 1 1 0, 1 1 1)),
  ((1 1 1, 1 1 0, 0 1 0, 0 1 1, 1 1 1))
)

28.2. Функції для 3D

Існує низка функцій, створених для обчислення взаємозв’язків між тривимірними об’єктами:

  • ST_3DClosestPoint — повертає тривимірну точку на об’єкті g1, яка є найближчою до об’єкта g2. Це перша точка найкоротшої 3D лінії.

  • ST_3DDistance — для типу geometry повертає мінімальну тривимірну евклідову відстань (на основі просторової системи координат) між двома геометріями в одиницях проекції.

  • ST_3DDWithin — для тривимірних (z) геометрій повертає true, якщо відстань між двома геометріями у 3D просторі не перевищує задану кількість одиниць.

  • ST_3DDFullyWithin — повертає true, якщо всі тривимірні геометрії знаходяться в межах заданої відстані одна від одної.

  • ST_3DIntersects — повертає TRUE, якщо геометрії «просторово перетинаються» у 3D — працює лише для точок та лінійних рядків (linestrings)

  • ST_3DLongestLine — повертає найтривалішу тривимірну лінію між двома геометріями

  • ST_3DMaxDistance — для типу geometry повертає максимальну тривимірну евклідову відстань (на основі просторової системи координат) між двома геометріями в одиницях проекції.

  • ST_3DShortestLine — повертає найкоротшу тривимірну лінію між двома геометріями

Наприклад, ми можемо обчислити відстань між нашим кубом зі стороною 1 та точкою за допомогою функції ST_3DDistance:

-- This is really the distance between the top corner
-- and the point.
SELECT ST_3DDistance(
  'POLYHEDRALSURFACE Z (
    ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),
    ((0 0 0, 0 1 0, 0 1 1, 0 0 1, 0 0 0)),
    ((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)),
    ((1 1 1, 1 0 1, 0 0 1, 0 1 1, 1 1 1)),
    ((1 1 1, 1 0 1, 1 0 0, 1 1 0, 1 1 1)),
    ((1 1 1, 1 1 0, 0 1 0, 0 1 1, 1 1 1))
  )'::geometry,
  'POINT Z (2 2 2)'::geometry
);

-- So here's a shorter form.
SELECT ST_3DDistance(
  'POINT Z (1 1 1)'::geometry,
  'POINT Z (2 2 2)'::geometry
);

-- Both return 1.73205080756888 == sqrt(3) as expected

28.3. N-вимірні індекси

Коли у вас є дані в багатовимірному форматі, може мати сенс їх індексувати. Проте варто ретельно обдумати розподіл ваших даних у всіх вимірах перед застосуванням багатовимірного індексу.

Індекси корисні лише тоді, коли вони дозволяють базі даних значно зменшити кількість рядків у результаті умови WHERE. Щоб багатовимірний індекс був ефективним, дані мають охоплювати широкий діапазон по відповідному виміру відносно типів запитів, які ви формуєте.

  • Набір точок DEM, ймовірно, буде поганим кандидатом для 3D-індексу, оскільки запити зазвичай витягують двовимірну область точок і рідко намагаються вибрати зріз по осі Z.

  • Набір GPS-треків у просторі X/Y/T може бути хорошим кандидатом для 3D-індексу, якщо GPS-шляхи часто перекриваються у всіх вимірах (наприклад, багаторазове проїзджання того самого маршруту в різний час), оскільки в наборі даних буде велика варіабельність у всіх вимірах.

Ви можете створити багатовимірний індекс для даних будь-якої розмірності (навіть змішаної). Наприклад, щоб створити багатовимірний індекс для таблиці nyc_streets,

CREATE INDEX nyc_streets_gix_nd ON nyc_streets
USING GIST (geom gist_geometry_ops_nd);

Параметр gist_geometry_ops_nd вказує PostGIS використовувати N-вимірний індекс замість стандартного 2-вимірного індексу.

Після створення індексу ви можете використовувати його в запитах з оператором індексу &&&. Оператор &&& має таке саме значення, як і && — «обмежувальні коробки взаємодіють», але застосовує ці правила до всіх вимірів вхідних геометрій. Геометрії з різною кількістю вимірів не взаємодіють.

-- Returns true (both 3-D on the zero plane)
SELECT 'POINT Z (1 1 0)'::geometry &&&
       'POLYGON ((0 0 0, 0 2 0, 2 2 0, 2 0 0, 0 0 0))'::geometry;

-- Returns false (one 2-D one 3-D)
SELECT 'POINT Z (3 3 3)'::geometry &&&
       'POLYGON ((0 0, 0 2, 2 2, 2 0, 0 0))'::geometry;

-- Returns true (the volume around the linestring interacts with the point)
SELECT 'LINESTRING Z(0 0 0, 1 1 1)'::geometry &&&
       'POINT(0 1 1)'::geometry;

Щоб виконати пошук у таблиці ``nyc_streets `` із використанням N-вимірного індексу, просто замініть звичайний оператор 2D-індексу ``&& `` на оператор ``&&& ``.

-- N-D index operator
SELECT gid, name
FROM nyc_streets
WHERE geom &&&
      ST_SetSRID('LINESTRING(586785 4492901,587561 4493037)'::geometry,26918);

-- 2-D index operator
SELECT gid, name
FROM nyc_streets
WHERE geom &&
      ST_SetSRID('LINESTRING(586785 4492901,587561 4493037)'::geometry,26918);

Результати мають бути однаковими. Загалом, N-вимірний індекс працює трохи повільніше за 2-вимірний, тому використовуйте N-вимірний індекс лише тоді, коли впевнені, що багатовимірні запити покращать селективність ваших запитів.