## Miller Cylindrical Projection with source for (Long, Lat) to (x, y)

Wednesday, May 2nd, 2012

Recently I have been trying to get a custom map working with Longitude and Latitude that plotted in the x and y in iOS. It also needed to work with a zoom and offset. It was a bit of an argus journey but I got there in the end.

What you will need is a projections type(map type) and the formula for the conversion. Ideally a projection type that compensates for the curvature of the earth.

I settled for a Miller Cylindrical projection. The problem with the maps is finding an accurate map. You can use maps with offsets but getting started it helps if you have an accurate map. I ended up going through a lot of maps before I found an accurate one. It had a white border that I had to crop off but otherwise it was perfect.

DONT FORGET TO CROP THE WHITE BOARDER IF YOU SCALE IT UP

http://en.wikipedia.org/wiki/File:Miller_projection_SW.jpg

I scaled it up for testing purposes up to a height of 6563 and a width 8933 cropped.

Here is the Objective-C code and little C to get he job done:

[objc]
//add this at the top of your m file with the rest
#import

// this simple c function can go under the imports and above the @implementation
CGFloat DegreesToRadians(CGFloat degrees){ return degrees * M_PI / 180;};

//you can use this method to do the conversion
– (CGPoint)XYfromLong:(float)lon andLat:(float)lat
{
double x, y;

//replace this with the height and width of you image
double height = 6563;
double width = 8933;

lon = DegreesToRadians(lon);
lat = DegreesToRadians(lat);

x = lon;
y = 1.25 * log( tan( 0.25 * M_PI + 0.4 * lat ) );

x = (( width / 2 ) + ( width / (2 * M_PI) ) * x);
y = ( height / 2 ) – ( height / ( 2 * 2.303412543 ) ) * y;

return CGPointMake(x,y);
}
[/objc]

As you can see the the hight and width is hard coded. What if your map needs an offset and you also need to have a dynamic size to compensate for zoom levels.

[objc]
//add this at the top of your m file with the rest
#import

// this simple c function can go under the imports and above the @implementation
CGFloat DegreesToRadians(CGFloat degrees){ return degrees * M_PI / 180;};

//you can use this method to do the conversion
– (CGPoint)XYfromLong:(float)lon andLat:(float)lat
{
double x, y;

//the height and width need to be set dynamically in your code
double height = dynamicHeightValue;
double width = dynamicWidthValue;

//you get the offset value by calculating the number of pixels it
//needs to be moved in the y then divide that by the map height
//it is unlikely the y will need an offset
double heightOffset = (height * 0.0243)

//you get the offset value by calculating the number of pixels it
//needs to be moved in the x then divide that by the map width
double widthOffset = (width * 0.0461)

lon = DegreesToRadians(lon);
lat = DegreesToRadians(lat);

x = lon;
y = 1.25 * log( tan( 0.25 * M_PI + 0.4 * lat ) );

x = (( width / 2 ) + ( width / (2 * M_PI) ) * x) – widthOffset;
y = (( height / 2 ) – ( height / ( 2 * 2.303412543 ) ) * y) – heightOffset;

return CGPointMake(x,y);
}
[/objc]