16. Проекція даних

Земля не є пласкою, і немає простого способу зобразити її на плоскому паперовому мапі (або на екрані комп’ютера), тому люди придумали різноманітні винахідливі рішення, кожне з яких має свої переваги і недоліки. Деякі проекції зберігають площу, тож усі об’єкти мають відносний розмір один до одного; інші проекції зберігають кути (конформні), як, наприклад, проекція Меркатора; деякі проекції намагаються знайти хороший проміжний варіант із мінімальними спотвореннями по кількох параметрах. Спільним для всіх проекцій є те, що вони трансформують (сферичний) світ у плоску декартову систему координат, а вибір проекції залежить від того, як ви плануєте використовувати ці дані.

Ми вже зустрічали проекції, коли завантажували наші дані Нью-Йорка — пам’ятаєте той нав’язливий SRID 26918? Іноді, однак, потрібно трансформувати та повторно проектувати між системами просторових координат. PostGIS має вбудовану підтримку зміни проекції даних за допомогою функції ST_Transform(geometry, srid). Для керування ідентифікаторами просторових систем координат (SRID) у геометріях, PostGIS надає функції ST_SRID(geometry) та ST_SetSRID(geometry, srid).

Ми можемо підтвердити SRID наших даних за допомогою функції ST_SRID:

SELECT ST_SRID(geom) FROM nyc_streets LIMIT 1;
26918

А що таке визначення «26918»? Як ми бачили у розділі «:ref: завантаження даних <loading_data>», це визначення міститься у таблиці spatial_ref_sys. Насправді, там є дві версії визначення. Визначення у форматі «well-known text» (WKT) знаходиться у стовпці srtext, а друга версія у форматі «proj.4» — у стовпці proj4text.

SELECT * FROM spatial_ref_sys WHERE srid = 26918;

Механізм перепроектування PostGIS спробує знайти найкращу проекцію з таблиці spatial_ref_sys:

  • auth_name / auth_srid Якщо proj може знайти дійсне «authority name» та «authority srid» у своєму внутрішньому каталозі, він використає їх для створення визначення проекції.

  • srtext Якщо proj може проаналізувати та сформувати об’єкт визначення з srtext, він буде використовувати його.

  • proj4text Зрештою, proj спробує обробити proj4text.

Вся ця надмірність означає, що для створення нової проекції в PostGIS вам потрібно лише дійсний рядок srtext або proj4text. Усі поширені пари назв/кодів органів влади вже завантажені в таблицю за замовчуванням.

Якщо у вас є вибір під час створення власного проектування, заповніть стовпець «srtext», оскільки цей стовпець також використовується зовнішніми програмами, такими як «GeoServer <http://geoserver.org>», «QGIS <https://qgis.org>» та «FME <http://www.safe.com/>» та іншими.

16.1. Порівняння даних

Разом координати та SRID визначають місце на земній кулі. Без SRID координати є лише абстрактним поняттям. «Декартова» координатна площина визначається як «плоска» система координат, розміщена на поверхні Землі. Оскільки функції PostGIS працюють на такій площині, операції порівняння вимагають, щоб обидві геометрії були представлені в одному SRID.

Якщо ви введете геометрії з різними SRID, ви отримаєте помилку:

SELECT ST_Equals(
         ST_GeomFromText('POINT(0 0)', 4326),
         ST_GeomFromText('POINT(0 0)', 26918)
         );
ERROR:  ST_Equals: Operation on mixed SRID geometries (Point, 4326) != (Point, 26918)

Примітка

Будьте обережні, не захоплюйтеся використанням команди ST_Transform для перетворення на льоту. Просторові індекси будуються з використанням SRID збережених геометрій. Якщо порівняння виконується в іншому SRID, просторові індекси (часто) не використовуються. Найкраще вибрати один SRID для всіх таблиць у вашій базі даних. Використовуйте функцію перетворення тільки під час читання або запису даних у зовнішні додатки.

16.2. Перетворення даних

Якщо повернутися до нашого визначення proj4 для SRID 26918, ми побачимо, що наша робоча проекція — це UTM (універсальна поперечна проекція Меркатора) зони 18, з метрами як одиницею вимірювання.

SELECT srtext FROM spatial_ref_sys WHERE srid = 26918;
PROJCS["NAD83 / UTM zone 18N",
  GEOGCS["NAD83",
    DATUM["North_American_Datum_1983",
      SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],
      TOWGS84[0,0,0,0,0,0,0],
      AUTHORITY["EPSG","6269"]],
    PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],
    UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],
    AUTHORITY["EPSG","4269"]],
  PROJECTION["Transverse_Mercator"],
  PARAMETER["latitude_of_origin",0],
  PARAMETER["central_meridian",-75],
  PARAMETER["scale_factor",0.9996],
  PARAMETER["false_easting",500000],
  PARAMETER["false_northing",0],
  UNIT["metre",1,AUTHORITY["EPSG","9001"]],
  AXIS["Easting",EAST],AXIS["Northing",NORTH],
  AUTHORITY["EPSG","26918"]]

Давайте перетворимо деякі дані з нашої робочої проекції в географічні координати, також відомі як «довгота/широта».

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

Найпоширенішим SRID для географічних координат є 4326, що відповідає «довготі/широті на сфероїді WGS84». Ви можете ознайомитися з визначенням тут:

Ви також можете витягти визначення з таблиці spatial_ref_sys:

SELECT srtext FROM spatial_ref_sys WHERE srid = 4326;
GEOGCS["WGS 84",
  DATUM["WGS_1984",
    SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],
    AUTHORITY["EPSG","6326"]],
  PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],
  UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],
  AUTHORITY["EPSG","4326"]]

Перетворимо координати станції метро «Broad St» у географічні:

SELECT ST_AsText(ST_Transform(geom,4326))
FROM nyc_subway_stations
WHERE name = 'Broad St';
POINT(-74.01067146887341 40.70710481558761)

Якщо ви завантажуєте дані або створюєте нову геометрію без вказання SRID, значення SRID буде 0. Згадайте в Geometries, що коли ми створювали нашу таблицю geometries, ми не вказали SRID. Якщо ми зробимо запит до нашої бази даних, ми повинні очікувати, що всі таблиці nyc_ матимуть SRID 26918, тоді як таблиця geometries за замовчуванням матиме SRID 0.

Щоб переглянути призначення SRID таблиці, виконайте запит до таблиці geometry_columns бази даних.

SELECT f_table_name AS name, srid
FROM geometry_columns;
        name         | srid
---------------------+-------
 nyc_census_blocks   | 26918
 nyc_homicides       | 26918
 nyc_neighborhoods   | 26918
 nyc_streets         | 26918
 nyc_subway_stations | 26918
 geometries          |     0

Однак, якщо ви знаєте, яким має бути SRID координат, ви можете встановити його постфактум, використовуючи ST_SetSRID на геометрії. Після цього ви зможете перетворити геометрію в інші системи.

SELECT ST_AsText(
    ST_Transform(
      ST_SetSRID(geom,26918),
      4326)
    )
  FROM geometries;

16.3. Список функцій

ST_AsText: Повертає представлення геометрії/географії у вигляді добре відомого тексту (WKT) без метаданих SRID.

ST_SetSRID(geometry, srid): Встановлює SRID для геометрії на певне ціле значення.

ST_SRID(geometry): Повертає ідентифікатор просторового посилання для ST_Geometry, як визначено в таблиці spatial_ref_sys.

ST_Transform(geometry, srid): Повертає нову геометрію з координатами, перетвореними у SRID, на який посилається цілочисельний параметр.