No exact solution exists
There is no isometric map from the sphere to the plane. When you convert lat/lon coordinates from the sphere to x/y coordinates in the plane, you cannot hope that all lengths will be preserved by this operation. You have to accept some kind of deformation. Many different map projections do exist, which can achieve different compromises between preservations of lengths, angles and areas. For smallish parts of earth's surface, transverse Mercator is quite common. You might have heard about UTM. But there are many more.
The formulas you quote compute x/y/z, i.e. a point in 3D space. But even there you'd not get correct distances automatically. The shortest distance between two points on the surface of the sphere would go through that sphere, whereas distances on the earth are mostly geodesic lengths following the surface. So they will be longer.
Approximation for small areas
If the part of the surface of the earth which you want to draw is relatively small, then you can use a very simple approximation. You can simply use the horizontal axis x to denote longitude Ξ», the vertical axis y to denote latitude Ο. The ratio between these should not be 1:1, though. Instead you should use cos(Ο0) as the aspect ratio, where Ο0 denotes a latitude close to the center of your map. Furthermore, to convert from angles (measured in radians) to lengths, you multiply by the radius of the earth (which in this model is assumed to be a sphere).
- x = r Ξ» cos(Ο0)
- y = r Ο
This is simple equirectangular projection. In most cases, you'll be able to compute cos(Ο0) only once, which makes subsequent computations of large numbers of points really cheap.
Answer from MvG on Stack OverflowNo exact solution exists
There is no isometric map from the sphere to the plane. When you convert lat/lon coordinates from the sphere to x/y coordinates in the plane, you cannot hope that all lengths will be preserved by this operation. You have to accept some kind of deformation. Many different map projections do exist, which can achieve different compromises between preservations of lengths, angles and areas. For smallish parts of earth's surface, transverse Mercator is quite common. You might have heard about UTM. But there are many more.
The formulas you quote compute x/y/z, i.e. a point in 3D space. But even there you'd not get correct distances automatically. The shortest distance between two points on the surface of the sphere would go through that sphere, whereas distances on the earth are mostly geodesic lengths following the surface. So they will be longer.
Approximation for small areas
If the part of the surface of the earth which you want to draw is relatively small, then you can use a very simple approximation. You can simply use the horizontal axis x to denote longitude Ξ», the vertical axis y to denote latitude Ο. The ratio between these should not be 1:1, though. Instead you should use cos(Ο0) as the aspect ratio, where Ο0 denotes a latitude close to the center of your map. Furthermore, to convert from angles (measured in radians) to lengths, you multiply by the radius of the earth (which in this model is assumed to be a sphere).
- x = r Ξ» cos(Ο0)
- y = r Ο
This is simple equirectangular projection. In most cases, you'll be able to compute cos(Ο0) only once, which makes subsequent computations of large numbers of points really cheap.
I want to share with you how I managed the problem. I've used the equirectangular projection just like @MvG said, but this method gives you X and Y positions related to the globe (or the entire map), this means that you get global positions. In my case, I wanted to convert coordinates in a small area (about 500m square), so I related the projection point to another 2 points, getting the global positions and relating to local (on screen) positions, just like this:
First, I choose 2 points (top-left and bottom-right) around the area where I want to project, just like this picture:

Once I have the global reference area in lat and lng, I do the same for screen positions. The objects containing this data are shown below.
//top-left reference point
var p0 = {
scrX: 23.69, // Minimum X position on screen
scrY: -0.5, // Minimum Y position on screen
lat: -22.814895, // Latitude
lng: -47.072892 // Longitude
}
//bottom-right reference point
var p1 = {
scrX: 276, // Maximum X position on screen
scrY: 178.9, // Maximum Y position on screen
lat: -22.816419, // Latitude
lng: -47.070563 // Longitude
}
var radius = 6371; //Earth Radius in Km
//## Now I can calculate the global X and Y for each reference point ##\\
// This function converts lat and lng coordinates to GLOBAL X and Y positions
function latlngToGlobalXY(lat, lng){
//Calculates x based on cos of average of the latitudes
let x = radius*lng*Math.cos((p0.lat + p1.lat)/2);
//Calculates y based on latitude
let y = radius*lat;
return {x: x, y: y}
}
// Calculate global X and Y for top-left reference point
p0.pos = latlngToGlobalXY(p0.lat, p0.lng);
// Calculate global X and Y for bottom-right reference point
p1.pos = latlngToGlobalXY(p1.lat, p1.lng);
/*
* This gives me the X and Y in relation to map for the 2 reference points.
* Now we have the global AND screen areas and then we can relate both for the projection point.
*/
// This function converts lat and lng coordinates to SCREEN X and Y positions
function latlngToScreenXY(lat, lng){
//Calculate global X and Y for projection point
let pos = latlngToGlobalXY(lat, lng);
//Calculate the percentage of Global X position in relation to total global width
pos.perX = ((pos.x-p0.pos.x)/(p1.pos.x - p0.pos.x));
//Calculate the percentage of Global Y position in relation to total global height
pos.perY = ((pos.y-p0.pos.y)/(p1.pos.y - p0.pos.y));
//Returns the screen position based on reference points
return {
x: p0.scrX + (p1.scrX - p0.scrX)*pos.perX,
y: p0.scrY + (p1.scrY - p0.scrY)*pos.perY
}
}
//# The usage is like this #\\
var pos = latlngToScreenXY(-22.815319, -47.071718);
$point = $("#point-to-project");
$point.css("left", pos.x+"em");
$point.css("top", pos.y+"em");
As you can see, I made this in javascript, but the calculations can be translated to any language.
P.S. I'm applying the converted positions to an HTML element whose id is "point-to-project". To use this piece of code on your project, you shall create this element (styled as position absolute) or change the "usage" block.
Converting latitude and longitude to XY coordinates
excel - Formula for X & Y Co-ordinates to Latitude and Longitude? - Stack Overflow
map projections - Conversion of coordinates (longitude ; latitude) to (X;Y) - Mathematics Stack Exchange
python - How to convert latitude and longitude to x and y grid system? - Stack Overflow
Videos
You have so many parentheses in your latitude formula that itβs hard to see what goes with what.
Let $\phi = \mathrm{LatY} \times \frac\pi{180},$ that is, if LatY is the latitude in degrees then $\phi$ is the latitude in radians. Let $h$ be mapHeight and let $w$ be mapWidth. Then your formula for $y$ becomes this in mathematical notation: $$ y = \frac h2 - \frac{w \ln\left(\tan\left(\frac\pi4 + \frac\phi2\right)\right) }{2 \pi} $$
This is similar to the formula found at http://mathworld.wolfram.com/MercatorProjection.html except for the scaling and translation factors (which you want in order to fit the output on the display).
Solving the equation for $\phi$ (still in radians), $$ \phi = 2 \arctan\left(\exp\left(\frac{2\pi}{w} \left(\frac h2 - y \right) \right)\right) - \frac\pi2. $$ Multiply by $\frac{180}{\pi}$ to get the answer in degrees.
Again itβs hard to be sure due to the profusion of parentheses, but the attempted formula seems to be equivalent to the mathematical equation
$$ \mathrm{lat} = \frac{\exp\left(-\frac{\left(Y - \frac h2 \right)}{w} \times 2 \pi \right) - \tan\left(\frac\pi4\right) \times 2}{\pi / 180}, $$
which is clearly quite different. The fact that $\tan\left(\frac\pi4\right)$ (which is just equal to $1$) occurs in there should be a red flag indicating that something was done in the wrong order.
Can't spot the issue with the final equation but reverse engineering the y = equation will work. Doing that you end up with the following:
lat = ((Math.arctan(Math.exp((((mapHeight / 2) -y) / mapWidth) * (2 * Math.PI))) - (Math.PI / 4))*2)/(Math.PI/180)
The following gets you pretty close (answer in km). If you need to be better than this, you have to work harder at the math - for example by following some of the links given.
import math
dx = (lon1-lon2)*40000*math.cos((lat1+lat2)*math.pi/360)/360
dy = (lat1-lat2)*40000/360
Variable names should be pretty obvious. This gives you
dx = 66.299 km (your link gives 66.577)
dy = 2.222 km (link gives 2.225)
Once you pick coordinates (for example, lon1, lat1) as your origin, it should be easy to see how to compute all the other XY coordinates.
Note - the factor 40,000 is the circumference of the earth in km (measured across the poles). This gets you close. If you look at the source of the link you provided (you have to dig around a bit to find the javascript which is in a separate file) you find that they use a more complex equation:
function METERS_DEGLON(x)
{
with (Math)
{
var d2r=DEG_TO_RADIANS(x);
return((111415.13 * cos(d2r))- (94.55 * cos(3.0*d2r)) + (0.12 * cos(5.0*d2r)));
}
}
function METERS_DEGLAT(x)
{
with (Math)
{
var d2r=DEG_TO_RADIANS(x);
return(111132.09 - (566.05 * cos(2.0*d2r))+ (1.20 * cos(4.0*d2r)) - (0.002 * cos(6.0*d2r)));
}
}
It looks to me like they are actually taking account of the fact that the earth is not exactly a sphere... but even so when you are making the assumption you can treat a bit of the earth as a plane you are going to have some errors. I'm sure with their formulas the errors are smaller...
UTM projections are in meters. So you could use something like the utm lib at this link:
https://pypi.python.org/pypi/utm
Googling python lat lon to UTM will point to several options.
UTM zones are 6 degrees of longitude wide and start from 0 at the prime meridian. The origin of each UTM zone is on the equator (x-axis) with the y-axis at the western most degree of longitude. This makes the grid positive to the north and east. You could calculate your distance from these results. Values are most accurate in the middle of the UTM zone.
You also should know what datum your original lat lon values are based on and use the same datum in your conversion.
Hello all.
I'm a programmer who has just about zero experience with GIS. I am currently working on a project that contains a local map of a fairly small area.
This map needs to be populated with points of interest relevant to the customer.
Because of some licensing issue I can't make use of any of the common map api's that you would normally use for this. I will need to convert Lat/Long to the XY coordinate system of the unreal engine.
To do this I have been given a map image, the Lat/Long coord's for the topleft and bottomright corner of the image, and a list of lat/long coords for the points of interest.
Top left lat/long: 52.04176, 4.66225
Bottom right lat/long: 51.99592, 4.76227
Top left in Unreal: x=0.0, y=0.0
Bottom right in Unreal: x=800.0 y=600.0
I thought this would be easily done by just using the range, but I kinda forgot you have to account for the curvature of the earth so it doesn't work.
How do I convert this?
[edit]Used Solution
For flat screen projection you want to convert your coords to something called "Web Mercator"
Because of float rounding in Unreal I need to do the conversions before importing. I used excel to convert it.
X = [Earth's radius scaled to your map(6371 will do)] * long * cos(lat for center of your map)
Y = [Earth's radius scaled to your map] * lat * -1
Figure out the range of your coordinates and use that to normalize the import to 0-1, multiply by size of your map to get unreal coordinates.
[/edit]
I would like to know if there is a way to convert a latitude and longitude, for example, (14.614792935634199,-90.54058565960504), to an X Y coordinate system. And what is the correct way to convert them? If you could share the formula with me, I would greatly appreciate it!
Update
If utm coordinates are suitable for your purposes, then note that in lieu of pyproj, the utm package is now available and is simpler to use. Just be aware of lng, lat ordering vs. easting, northing ordering for the respective from_latlon and to_latlon functions, per the docs.
The below conversion example would become:
import utm
x, y = utm.from_latlon(input_lat, input_lon)
Original
Use pyproj for converting your lng, lat pairs to a projected coordinate system. In other words you need to convert from your geographic coordinate system (most likely EPSG code 4326) to a local projected coordinate system, e.g. a local UTM zone or regional system such as the British National Grid (EPSG code 27700).
import pyproj as proj
# setup your projections
crs_wgs = proj.Proj(init='epsg:4326') # assuming you're using WGS84 geographic
crs_bng = proj.Proj(init='epsg:27700') # use a locally appropriate projected CRS
# then cast your geographic coordinate pair to the projected system
x, y = proj.transform(crs_wgs, crs_bng, input_lon, input_lat)
Note that pyproj.transform() also works on numpy arrays, so you can therefore transform your lon, lat arrays to x, y arrays. You can then use numpy's built-in array methods to normalise your values.
For example:
import numpy as np
x = (x - x.min()) / (x.max() - x.min())
y = (y - y.min()) / (y.max() - y.min())
However, if you are using sklearn already, then you may as well use sklearn.preprocessing.normalize.
It depends on what metric you need to preserve. One obvious approach is to project it to some appropriate flat coordinate system. To do this, you can use the pyproj library. Then, simply rescale your coordinates to be in the range [0, 1]. However, this doesn't perfectly preserve spatial relationships because longitude and latitude are on a sphere (or an ellipsoid or geoid), and x,y coordinates are on a flat surface. You should read about different map projections to see what you may be losing. A good reference is Map Projections: A Working Manual. If your positions only cover a small patch of the Earth, the errors may be acceptable to you.
A second approach is to convert the longitude and latitude to (x, y, z) coordinates in 3d space. If you approximate the earth's surface as a sphere, then the formulae should be
x = cos(lat) * cos(lon)
y = cos(lat) * sin(lon)
z = sin(lat)
where lon and lat are in radians. In this case however, z=-1 is the south pole, z=1 is the north pole, x=1 and x=-1 are the prime meridian, and the dateline, and y=1 and y=-1 are 90 degrees East and 90 degrees West. Again, you can rescale so that coordinates are [0,1] rather than [-1,1].
Here's what worked for me, without so much bs.
int x = (int) ((MAP_WIDTH/360.0) * (180 + lon));
int y = (int) ((MAP_HEIGHT/180.0) * (90 - lat));
The lat,lon coordinates were given to me by Android devices. So they should be in the same standard used by all Google Earth/Map products.
If using the Equidistant Cylindrical Projection type map, here is what you need to do:
- Find the Latitude and longitude of your location tutorial here:
http://lifehacker.com/267361/how-to-find-latitude-and-longitude - Input that information into the following formulas:
x = (total width of image in px) * (180 + latitude) / 360
y = (total height of image in px) * (90 - longitude) / 180
note: when using negative longitude of latitude make sure to add or subtract the negative number i.e. +(-92) or -(-35) which would actually be -92 and +35
- You now have your X and Y to plot on your image
More information can be found about this formula and the map type here:
http://www.progonos.com/furuti/MapProj/Dither/CartHow/HowER_W12/howER_W12.html#DeductionEquirectangular
