Введение
Цифровые модели поверхности и рельефа (ЦМП/ЦМР) – являются важной и неотъемлемой составляющей геоинформационных систем (ГИС). Они являются источником высотной информации и решают задачу определения высоты Z в указанной точке с координатами XY на местности. ЦМП и ЦМР могут быть как регулярными, так и нерегулярными (чаще всего их делят по формату хранения высотных отметок (растровые и векторные). Растровые ЦМП/ЦМР чаще всего поставляются в виде геопривязанного растра с типом пиксельных значений позволяющих хранить дробные отрицательные числа (32-bit float). Повсеместная реализация и внедрение информационных сервисов (прежде всего онлайн), делает необходимым отображение пользователям высотной информации в интерактивном режиме (определение Z при перемещении курсора XY) и ставит перед разработчиком задачу донесения этой информации. Если в случае с векторными данными, мы можем отобразить высотный пикет в координатах XY и показать записанный ему атрибут Z, то с растровыми (регулярными) моделями высот такое не выйдет, иначе мы должны хранить атрибут на каждый пиксель нашего растра (так никто не делает) или быть готовыми его рассчитать и вернуть пользователю с сервера. В принципе, эта задача решена показом на растровых тайлах высотных отметок или горизонталей в виде рисунка, но такой способ отображения высот не интерактивен и несет лишнюю нагрузку на картографическую составляющую тайлов.
Проблема
Если перед пользователем стоит задача определения высоты Z в точке с конкретными координатами на местности XY, то скорее всего решением со стороны разработчика будет состоять в отправке запроса на сервер с координатами XY клика (или действия пользователя), на сервере выполнятся какие-то запросы (SQL) или скрипты и пользователю вернется ответ. Запросы или скрипты на сервере могут быть разной сложности, что добавляет времени и затрачивает вычислительные ресурсов сервера для формирования ответа.
Можно пользователю отдавать исходные 32 битные (float) ЦМП/ЦМР тайлы и считывать пиксельные значения Z из координат XY курсора (и растра), 32-бит тяжело для передачи и отображения на сервисе и, честно говоря, хочется простого и красивого решения (вопрос спорный, получилось ли у нас?).
Постановка задачи
Нас оба таких способа не устраивают. Мы решили, что будем в реальном времени рассчитывать и показывать отметки высот под маркером пользователя, не нагружая сервер лишними запросами и передачей трафика. Наше решение должно удовлетворять следующим условиям:
Необходимо использовать только уже поддерживаемые форматы данных (у нас это png (xyz tiles) и geojson);
Исключить сервер для расчета высотной информации при работе пользователя с сервисом;
Максимально экономить на трафике при передаче высотной информации;
-
Реализовать интерактивную возможность (при перемещении курсора мыши 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). При этом мы не должны потерять знак высоты (высоты бывают отрицательными и положительными) и дробную часть. Мы решили реализовать следующие технологию:
Берем исходную (32 float) ЦМП или ЦМР;
Готовим исходный PNG файл: проходим по каждому пикселю нашей исходной ЦМП или ЦМР и кодируем ее 3 значениями RGB (8 integer);
Нарезаем PNG растр на тайлы (XYZ) и отдаем пользователю как обычный XYZ tiles;
Frontend отображает PNG тайлы с помощью leaflet.js (без необходимости использования или написания дополнительных плагинов для специфических форматов);
При перемещении пользователем курсора мыши XY считываем RGB значения пикселя тайла XY и переводим их в отметку высоты Z;
Выводим пользователю значение высоты 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.
Диапазон значений высот, которые мы можем записать таким способом [-65025.99, 65025.99]. Этого диапазона должно хватить для кодирования отметок любой высоты в пределах Солнечной системы. Мы используем описанную выше технологию для интерактивного отображения высот в нашем сервисе.
Комментарии (4)
mbeloshitsky
12.09.2022 15:34+2Привет. Мы в свое время тоже выбирали как кодировать тайлы DEM-тайлы и в итоге пришли к хранению в бинарного массива 16-битных чисел, с одной особенностью - сначала идут все старшие байты, а потом все младшие. В качестве сжатия положились на gzip, которым жмет тайлы веб-сервер.
Это не совсем стандартный формат, который однако потребовал у нас меньше ресурсов на распаковку (не нужно создавать канвас, потом рисовать на нем PNG и читать пикселы). Вот наше исследование на этот счет, возможно оно сможет показаться вам полезным https://observablehq.com/@itanka10/relief-tiles-stats
freeExec
Да ну вы чего, уже сто лет кодируют RGB
docs.mapbox.com/data/tilesets/guides/access-elevation-data/#example-decode-elevation-data-in-a-terrain-rgb-tile
brusnika777 Автор
Да уж, изобрели велосипед)