**Get started with Spring 5 and Spring Boot 2, through the ***Learn Spring* course:

*Learn Spring*course:

**>> CHECK OUT THE COURSE**

Last modified: March 25, 2020

When implementing applications that use maps, we will typically run into the problem of coordinate conversion. Most of the time, we need to** convert latitude and longitude to a 2D point to display**. Fortunately, to solve this problem, we can utilize the formulas of the Mercator projection.

In this tutorial, we'll cover the Mercator Projection and will learn how to implement its two variants.

The Mercator projection is a map projection introduced by the Flemish cartographer Gerardus Mercator in 1569. A map projection converts latitude and longitude coordinates on the Earth to a point on a flat surface. In other words, **it translates a point on the surface of the earth to a point on a flat map**.

There are two ways of implementing the Mercator projection. **The pseudo Mercator projection treats the Earth as a sphere. The true Mercator projection models the Earth as an ellipsoid**. We will implement both versions.

Let's start with a base class for both Mercator projection implementations:

```
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);
}
```

This class also provides the major and the minor radius of Earth measured in meters. It is well known that Earth is not exactly a sphere. For that reason, we need two radiuses. Firstly, the **major radius is the distance from the center of the earth to the equator**. Secondly, the **minor radius is the distance from the center of the earth to the north and south poles**.

The pseudo-projection model treats the earth as a sphere. In contrast to the elliptical projection where the Earth would be projected on a more accurate shape. This approach allows us a **quick estimation** to the more precise, but computational heavier elliptical projection. As a result of that, the direct **measurements of distances** in this projection will be approximate.

Furthermore, the proportions of the shapes on the map will marginally alter. As a result of that latitude and ratios of shapes of objects on the map like countries, lakes, rivers, etc. are not **precisely preserved**.

This is also called the Web Mercator projection – commonly used in web applications including Google Maps.

Let's implement this approach:

```
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;
}
}
```

The first thing to note on this approach is the fact that this approach represents the **radius** of the earth by **one constant** and not two as it really is. Secondly, we can see that we have implemented two functions to use for converting to **x-axis projection** and **y-axis projection**. In the class above we have used *Math* library provided by java to help us make our code simpler.

Let's test a simple conversion:

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

It is worth noting that this projection will map points into a bounding box (left, bottom, right, top) of (-20037508.34, -23810769.32, 20037508.34, 23810769.32).

The true projection models the earth as an ellipsoid. **This projection gives** **accurate ratios** **for objects anywhere on Earth**. Certainly,** it respects objects on the map but** **not 100% accurate**. However, this approach is not the most frequently used because it is computationally complex.

Let's implement this approach:

```
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);
}
}
```

Above we can see how complex this approach is regarding the projection on the y-axis. This is because it should take into consideration the non-round earth shape. Although the true Mercator approach seems complex, is more accurate than the spherical approach as it uses to radius for representing earth one minor and one major.

Let's test a simple conversion:

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

This projection will map points into a bounding box of (-20037508.34, -34619289.37, 20037508.34, 34619289.37).

If we need to convert latitude and longitude coordinates onto a 2D surface, we can use the Mercator projection. Depending on the accuracy we need for our implementation, we can use the spherical or elliptical approach.

As always, we can find the code of this article over on GitHub.

2 Comments

Oldest