Цифровая модель поверхности (ЦМП)
Цифровая модель поверхности (ЦМП)

Введение

Цифровые модели поверхности и рельефа (ЦМП/ЦМР) – являются важной и неотъемлемой составляющей геоинформационных систем (ГИС). Они являются источником высотной информации и решают задачу определения высоты Z в указанной точке с координатами XY на местности. ЦМП и ЦМР могут быть как регулярными, так и нерегулярными (чаще всего их делят по формату хранения высотных отметок (растровые и векторные). Растровые ЦМП/ЦМР чаще всего поставляются в виде геопривязанного растра с типом пиксельных значений позволяющих хранить дробные отрицательные числа (32-bit float). Повсеместная реализация и внедрение информационных сервисов (прежде всего онлайн), делает необходимым отображение пользователям высотной информации в интерактивном режиме (определение Z при перемещении курсора XY) и ставит перед разработчиком задачу донесения этой информации. Если в случае с векторными данными, мы можем отобразить высотный пикет в координатах XY и показать записанный ему атрибут Z, то с растровыми (регулярными) моделями высот такое не выйдет, иначе мы должны хранить атрибут на каждый пиксель нашего растра (так никто не делает) или быть готовыми его рассчитать и вернуть пользователю с сервера. В принципе, эта задача решена показом на растровых тайлах высотных отметок или горизонталей в виде рисунка, но такой способ отображения высот не интерактивен и несет лишнюю нагрузку на картографическую составляющую тайлов.

Отображение высотной информации (в виде горизонталей или подписей)
Отображение высотной информации (в виде горизонталей или подписей)

Проблема

Если перед пользователем стоит задача определения высоты Z в точке с конкретными координатами на местности XY, то скорее всего решением со стороны разработчика будет состоять в отправке запроса на сервер с координатами XY клика (или действия пользователя), на сервере выполнятся какие-то запросы (SQL) или скрипты и пользователю вернется ответ. Запросы или скрипты на сервере могут быть разной сложности, что добавляет времени и затрачивает вычислительные ресурсов сервера для формирования ответа.

Можно пользователю отдавать исходные 32 битные (float) ЦМП/ЦМР тайлы и считывать пиксельные значения Z из координат XY курсора (и растра), 32-бит тяжело для передачи и отображения на сервисе и, честно говоря, хочется простого и красивого решения (вопрос спорный, получилось ли у нас?).

Постановка задачи

Нас оба таких способа не устраивают. Мы решили, что будем в реальном времени рассчитывать и показывать отметки высот под маркером пользователя, не нагружая сервер лишними запросами и передачей трафика. Наше решение должно удовлетворять следующим условиям:

  1. Необходимо использовать только уже поддерживаемые форматы данных (у нас это png (xyz tiles) и geojson);

  2. Исключить сервер для расчета высотной информации при работе пользователя с сервисом;

  3. Максимально экономить на трафике при передаче высотной информации;

  4. Реализовать интерактивную возможность (при перемещении курсора мыши XY показывать пользователю высоту Z) определения высот при работе с сервисом.

    Поскольку основным для нашего сервиса растровым форматом является PNG, то мы будем использовать его. Мы работаем с 3 канальными 8 битными растровыми PNG. Пиксельные значения каждого из RGB каналов PNG, могут иметь значения в диапазоне [0…255], т.е. для каждого пикселя мы имеем 3 значения [[0…255], [0…255], [0…255]]. Мы должны записать высотную отметку (32 float) исходной ЦМП/ЦМР в соответствующий пиксель нашего PNG XYZ-tiles (8 integer x 3). При этом мы не должны потерять знак высоты (высоты бывают отрицательными и положительными) и дробную часть. Мы решили реализовать следующие технологию:

    1. Берем исходную (32 float) ЦМП или ЦМР;

    2. Готовим исходный PNG файл: проходим по каждому пикселю нашей исходной ЦМП или ЦМР и кодируем ее 3 значениями RGB (8 integer);

    3. Нарезаем PNG растр на тайлы (XYZ) и отдаем пользователю как обычный XYZ tiles;

    4. Frontend отображает PNG тайлы с помощью leaflet.js (без необходимости использования или написания дополнительных плагинов для специфических форматов);

    5. При перемещении пользователем курсора мыши XY считываем RGB значения пикселя тайла XY и переводим их в отметку высоты Z;

    6. Выводим пользователю значение высоты Z.

    Решение

    Для выполнения пункта 2 технологии нам необходимо рассчитать пиксельные значения PNG файла соответствующие значениями высоты исходной ЦМП/ЦМР. Исходные значение высоты Z (числитель), мы будем делить на 255 (знаменатель) и целое число от деления записывать в пиксельные значения канала R (т.е. если Z=60, то R=0, если Z=255, то R=1, если Z=546, то R = 2). Остаток от деления, мы будем записывать в канал G, т.е. для выше описанных случаев G= 60, G=0, G= 36. Таким образом формируя изображения из пиксельных значений высоты, мы можем кодировать любые целочисленные высоты. У нас остается еще один незаполненный канал B - сантиметры (см), она же, дробная часть в значениях высоты Z и знак отметки высот Z, которые мы пока с вами не рассматривали. Для себя мы решили, что для отрицательных высот мы будем назначать значения канала B=100, а для положительных значение канала B=0, а значения сантиметров высоты прибавлять к пиксельному значению канала B. То есть, для высот -0.5 м и 0.5 м, значения для канала B будут 150 и 50 соответственно.

    Ниже представлена таблица кодирования высот для значений пикселя тайлов в формате PNG.

    Пример пиксельных значений PNG-tiles для отметок высот 32-bit float
    Пример пиксельных значений PNG-tiles для отметок высот 32-bit float

    Диапазон значений высот, которые мы можем записать таким способом [-65025.99, 65025.99]. Этого диапазона должно хватить для кодирования отметок любой высоты в пределах Солнечной системы. Мы используем описанную выше технологию для интерактивного отображения высот в нашем сервисе.

Комментарии (4)


  1. freeExec
    12.09.2022 15:00

    1. brusnika777 Автор
      12.09.2022 15:57

      Да уж, изобрели велосипед)


  1. mbeloshitsky
    12.09.2022 15:34
    +2

    Привет. Мы в свое время тоже выбирали как кодировать тайлы DEM-тайлы и в итоге пришли к хранению в бинарного массива 16-битных чисел, с одной особенностью - сначала идут все старшие байты, а потом все младшие. В качестве сжатия положились на gzip, которым жмет тайлы веб-сервер.

    Это не совсем стандартный формат, который однако потребовал у нас меньше ресурсов на распаковку (не нужно создавать канвас, потом рисовать на нем PNG и читать пикселы). Вот наше исследование на этот счет, возможно оно сможет показаться вам полезным https://observablehq.com/@itanka10/relief-tiles-stats


    1. brusnika777 Автор
      12.09.2022 15:57

      Спасибо) обязательно посмотрим