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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
//add this at the top of your m file with the rest #import <math.h> // 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); } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
//add this at the top of your m file with the rest #import <math.h> // 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); } |