Выравнивание Natural Earth Geojson и растра для рендеринга в D3

Я пытаюсь отобразить карту мира с данными о высоте, используя D3.

Для этого я использую Natural Earth 50m land geojson: https://github.com/martynafford/natural-earth-geojson/tree/master/50m/physical

И растровые данные естественной высоты Земли: https://www.naturalearthdata.com/downloads/50m-raster-data/50m-shaded-relief/

Я использую этот учебник: https://datawanderings.com/2020/08/08/растровые фоны/

Итак, я сначала нашел границы геоджсона:

ogrinfo ne_50m_land.json -so -al | grep Extent  
Extent: (-180.000000, -89.998926) - (180.000000, 83.599609)

Затем я вырезал файл TIF:

gdal_translate -projwin -180.000000 83.599609 180.000000 -89.998926 SR_50M.tif SR_50M-box.tif

И спроецируйте в проекцию Меркатора:

gdalwarp -overwrite -s_srs "+proj=longlat +datum=WGS84 +no_defs" -t_srs EPSG:3395 SR_50M-box.tif SR_50M-proj.tif

Наконец, я экспортирую в PNG:

gdal_translate -of PNG SR_50M-proj.tif SR_50M.png

Затем я визуализирую все с помощью D3.

   this.projection = d3.geoMercator()
        .translate([0, 0])
        .scale(1)


   this.rasterImage = new Image();
   this.rasterImage.src = raster;

   this.path = d3.geoPath(this.projection, this.ctx);
   this.bb = this.path.bounds(this.land);

   const s = 1 / Math.max((this.bb[1][0] - this.bb[0][0]) / this.getWidth(), (this.bb[1][1] - this.bb[0][1]) / this.getHeight());
    // transform
   const t = [(this.getWidth() - s * (this.bb[1][0] + this.bb[0][0])) / 2, (this.getHeight() - s * (this.bb[1][1] + this.bb[0][1])) / 2];

    // update projection
   this.projection
       .scale(s)
       .translate(t);

   this.raster_width = (this.bb[1][0] - this.bb[0][0]) * s;
   this.raster_height = (this.bb[1][1] - this.bb[0][1]) * s;

   this.rtranslate_x = (this.getWidth() - this.raster_width) / 2;
   this.rtranslate_y = (this.getHeight() - this.raster_height) / 2;

   this.ctx.beginPath();
   this.path(this.land);
   this.ctx.fill();

   this.ctx.save();
   this.ctx.globalAlpha = 0.8;
   this.ctx.translate(this.rtranslate_x, this.rtranslate_y);
   this.ctx.drawImage(this.rasterImage, 0, 0, this.raster_width, this.raster_height);
   this.ctx.restore();

Однако в конце земля геоджсона и растр не выровнены:

Выравнивание Natural Earth Geojson и растра для рендеринга в D3

Я пытался сначала проецировать, а затем вырезать или использовать Псевдо-Меркатор или Меркатор при проецировании, но ничего не работает. У кого-нибудь есть идеи?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Меркатор обычно обрезается примерно на 85 градусах северной/южной широты (~85,05113 северной/южной широты) — чем дальше, тем выше вы получите карту, высота которой больше, чем ширина, и карта становится намного выше на каждый дополнительный градус севера/юга. входит в объем..

Функции клипов D3, использующие это ограничение:

The spherical Mercator projection. Defines a default projection.clipExtent such that the world is projected to a square, clipped to approximately ±85° latitude.

Северные границы в порядке, но южные границы геоджсона — это -89.998926 градусов, которые вы используете для вырезания изображения. Но поскольку D3 обрезает geojson, вы растягиваете изображение на другую величину по сравнению с geojson, отсюда и проблема, которую вы видите.

Решение должно состоять в том, чтобы обрезать изображение до границ, которые представляют пределы того, что D3 будет отображать для Меркатора (85.05113 градусов южной широты), а не пределы самих данных.

Я не смотрел, насколько точно gdal реализует EPSG:3395, поскольку определение предусматривает проецируемые границы 80 градусов на юг и 84 градуса на север - хотя, глядя на изображение, это не кажется проблемой.

Вы также можете использовать более чистые методы fitSize для проекций D3 (d3v4+):

 projection.fitSize([width,height],geojsonObject)

Который установит масштаб и переведет для вас заданную ширину/высоту.

Я обрезал изображение TIF, используя -85.05113 в качестве южной границы, и это работает! Есть еще очень незначительный сдвиг, но на данный момент этого достаточно. Спасибо

Alexis Pister 21.03.2022 14:17

Другие вопросы по теме