Преобразуване на географска ширина и дължина в 2D точка в Java

1. Общ преглед

Когато внедряваме приложения, които използват карти, обикновено ще срещнем проблема с преобразуването на координати. По-голямата част от времето трябва да преобразуваме географска ширина и дължина в 2D точка за показване . За щастие, за да разрешим този проблем, можем да използваме формулите на проекцията на Меркатор.

В този урок ще разгледаме проекцията на Меркатор и ще научим как да приложим двата й варианта.

2. Проекция на Меркатор

Проекцията на Меркатор е проекция на карта, въведена от фламандския картограф Герардус Меркатор през 1569 г. Проекцията на картата преобразува координатите на географска ширина и дължина на Земята в точка на равна повърхност. С други думи, той превежда точка на повърхността на земята в точка на плоска карта .

Има два начина за изпълнение на проекцията на Меркатор. Псевдо проекцията на Меркатор третира Земята като сфера. Истинската проекция на Меркатор моделира Земята като елипсоид . Ще внедрим и двете версии.

Нека започнем с основен клас за двете реализации на Mercator:

abstract class Mercator { final static double RADIUS_MAJOR = 6378137.0; final static double RADIUS_MINOR = 6356752.3142; abstract double yAxisProjection(double input); abstract double xAxisProjection(double input); }

Този клас също така предоставя основния и малкия радиус на Земята, измерени в метри. Добре известно е, че Земята не е точно сфера. Поради тази причина ни трябват два радиуса. Първо, големият радиус е разстоянието от центъра на земята до екватора . На второ място, малкият радиус е разстоянието от центъра на земята до северния и южния полюс .

2.1. Сферична проекция на Меркатор

Моделът на псевдопроекция третира земята като сфера. За разлика от елиптичната проекция, където Земята ще бъде проектирана с по-точна форма. Този подход ни позволява бърза оценка на по-прецизната, но изчислителна по-тежка елиптична проекция. В резултат на това преките измервания на разстоянията в тази проекция ще бъдат приблизителни.

Освен това пропорциите на фигурите на картата ще се променят незначително. В резултат на това географската ширина и съотношенията на формите на обектите на картата като страни, езера, реки и т.н. не са точно запазени .

Това се нарича още проекция на Web Mercator - често използвана в уеб приложения, включително Google Maps.

Нека приложим този подход:

public class SphericalMercator extends Mercator { @Override double xAxisProjection(double input) { return Math.toRadians(input) * RADIUS_MAJOR; } @Override double yAxisProjection(double input) { return Math.log(Math.tan(Math.PI / 4 + Math.toRadians(input) / 2)) * RADIUS_MAJOR; } }

Първото нещо, което трябва да се отбележи при този подход, е фактът, че този подход представлява радиуса на земята с една константа, а не с две, както е в действителност. На второ място, ние можем да видим, че сме изпълнени две функции да се използва за конвертиране на оста х проекция и ордината проекция . В класа по-горе използвахме Math библиотека, предоставена от java, за да ни помогне да улесним нашия код.

Нека тестваме просто преобразуване:

Assert.assertEquals(2449028.7974520186, sphericalMercator.xAxisProjection(22)); Assert.assertEquals(5465442.183322753, sphericalMercator.yAxisProjection(44));

Струва си да се отбележи, че тази проекция ще картографира точки в ограничаващо поле (вляво, отдолу, отдясно, отгоре) на (-20037508.34, -23810769.32, 20037508.34, 23810769.32).

2 .2. Елиптична проекция на Меркатор

Истинската проекция моделира земята като елипсоид. Тази проекция дава точни съотношения за обекти навсякъде по Земята . Разбира се, той зачита обектите на картата, но не е 100% точен . Този подход обаче не е най-често използваният, тъй като е изчислително сложен.

Нека приложим този подход:

class EllipticalMercator extends Mercator { @Override double yAxisProjection(double input) { input = Math.min(Math.max(input, -89.5), 89.5); double earthDimensionalRateNormalized = 1.0 - Math.pow(RADIUS_MINOR / RADIUS_MAJOR, 2); double inputOnEarthProj = Math.sqrt(earthDimensionalRateNormalized) * Math.sin( Math.toRadians(input)); inputOnEarthProj = Math.pow(((1.0 - inputOnEarthProj) / (1.0+inputOnEarthProj)), 0.5 * Math.sqrt(earthDimensionalRateNormalized)); double inputOnEarthProjNormalized = Math.tan(0.5 * ((Math.PI * 0.5) - Math.toRadians(input))) / inputOnEarthProj; return (-1) * RADIUS_MAJOR * Math.log(inputOnEarthProjNormalized); } @Override double xAxisProjection(double input) { return RADIUS_MAJOR * Math.toRadians(input); } }

По-горе можем да видим колко сложен е този подход по отношение на проекцията на оста y. Това е така, защото трябва да се вземе предвид некръглата земна форма. Въпреки че истинският подход на Меркатор изглежда сложен, той е по-точен от сферичния подход, тъй като използва радиус за представяне на земя една малка и една голяма.

Нека тестваме просто преобразуване:

Assert.assertEquals(2449028.7974520186, ellipticalMercator.xAxisProjection(22)); Assert.assertEquals(5435749.887511954, ellipticalMercator.yAxisProjection(44));

Тази проекция ще нанесе точки в ограничаващо поле на (-20037508.34, -34619289.37, 20037508.34, 34619289.37).

3 . Заключение

Ако трябва да преобразуваме координати на географска ширина и дължина върху 2D повърхност, можем да използваме проекцията на Меркатор. В зависимост от точността, от която се нуждаем за нашето изпълнение, можем да използваме сферичния или елиптичния подход.

Както винаги, можем да намерим кода на тази статия в GitHub.