{"id":389,"date":"2012-05-02T14:47:07","date_gmt":"2012-05-02T14:47:07","guid":{"rendered":"http:\/\/www.blogs.abeazam.com\/dev\/?p=389"},"modified":"2012-11-13T11:44:33","modified_gmt":"2012-11-13T11:44:33","slug":"miller-cylindrical-projection-with-source-for-long-lat-to-x-y","status":"publish","type":"post","link":"http:\/\/www.blogs.abeazam.com\/dev\/2012\/05\/miller-cylindrical-projection-with-source-for-long-lat-to-x-y\/","title":{"rendered":"Miller Cylindrical Projection with source for (Long, Lat) to (x, y)"},"content":{"rendered":"<p>Recently I have been trying to get a custom map working with Longitude\u00a0and\u00a0Latitude\u00a0that\u00a0plotted\u00a0in 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.<\/p>\n<p>What you will need is a projections type(map type) and the formula for the conversion.\u00a0Ideally a projection type that\u00a0compensates\u00a0for the curvature of the earth.<\/p>\n<p>I settled for a Miller\u00a0Cylindrical\u00a0projection. The problem with the maps is finding an\u00a0accurate map. You can use maps with offsets\u00a0but 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.<\/p>\n<p>DONT FORGET TO CROP THE WHITE BOARDER IF YOU SCALE IT UP<\/p>\n<p><a href=\"http:\/\/en.wikipedia.org\/wiki\/File:Miller_projection_SW.jpg\">http:\/\/en.wikipedia.org\/wiki\/File:Miller_projection_SW.jpg<\/a><\/p>\n<p>I scaled it up for testing purposes up to a height of 6563 and a width 8933\u00a0cropped.<\/p>\n<p>Here is the Objective-C code and little C to get he job done:<\/p>\n<p>[objc]<br \/>\n\/\/add this at the top of your m file with the rest<br \/>\n#import <math.h>\n<p>\/\/ this simple c function can go under the imports and above the @implementation<br \/>\nCGFloat DegreesToRadians(CGFloat degrees){ return degrees * M_PI \/ 180;};<\/p>\n<p>\/\/you can use this method to do the conversion<br \/>\n&#8211; (CGPoint)XYfromLong:(float)lon andLat:(float)lat<br \/>\n{<br \/>\ndouble x, y;<\/p>\n<p>\/\/replace this with the height and width of you image<br \/>\ndouble height = 6563;<br \/>\ndouble width = 8933;<\/p>\n<p>lon = DegreesToRadians(lon);<br \/>\nlat = DegreesToRadians(lat);<\/p>\n<p>x = lon;<br \/>\ny = 1.25 * log( tan( 0.25 * M_PI + 0.4 * lat ) );<\/p>\n<p>x = (( width \/ 2 ) + ( width \/ (2 * M_PI) ) * x);<br \/>\ny = ( height \/ 2 ) &#8211; ( height \/ ( 2 * 2.303412543 ) ) * y;<\/p>\n<p>return CGPointMake(x,y);<br \/>\n}<br \/>\n[\/objc]<\/p>\n<p>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.<\/p>\n<p>[objc]<br \/>\n\/\/add this at the top of your m file with the rest<br \/>\n#import <math.h>\n<p>\/\/ this simple c function can go under the imports and above the @implementation<br \/>\nCGFloat DegreesToRadians(CGFloat degrees){ return degrees * M_PI \/ 180;};<\/p>\n<p>\/\/you can use this method to do the conversion<br \/>\n&#8211; (CGPoint)XYfromLong:(float)lon andLat:(float)lat<br \/>\n{<br \/>\ndouble x, y;<\/p>\n<p>\/\/the height and width need to be set dynamically in your code<br \/>\ndouble height = dynamicHeightValue;<br \/>\ndouble width = dynamicWidthValue;<\/p>\n<p>\/\/you get the offset value by calculating the number of pixels it<br \/>\n\/\/needs to be moved in the y then divide that by the map height<br \/>\n\/\/it is unlikely the y will need an offset<br \/>\ndouble heightOffset = (height * 0.0243)<\/p>\n<p>\/\/you get the offset value by calculating the number of pixels it<br \/>\n\/\/needs to be moved in the x then divide that by the map width<br \/>\ndouble widthOffset = (width * 0.0461)<\/p>\n<p>lon = DegreesToRadians(lon);<br \/>\nlat = DegreesToRadians(lat);<\/p>\n<p>x = lon;<br \/>\ny = 1.25 * log( tan( 0.25 * M_PI + 0.4 * lat ) );<\/p>\n<p>x = (( width \/ 2 ) + ( width \/ (2 * M_PI) ) * x) &#8211; widthOffset;<br \/>\ny = (( height \/ 2 ) &#8211; ( height \/ ( 2 * 2.303412543 ) ) * y) &#8211; heightOffset;<\/p>\n<p>return CGPointMake(x,y);<br \/>\n}<br \/>\n[\/objc]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently I have been trying to get a custom map working with Longitude\u00a0and\u00a0Latitude\u00a0that\u00a0plotted\u00a0in 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 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[26,28,75,36,37,53],"tags":[79,78,77,76,101,81,80],"_links":{"self":[{"href":"http:\/\/www.blogs.abeazam.com\/dev\/wp-json\/wp\/v2\/posts\/389"}],"collection":[{"href":"http:\/\/www.blogs.abeazam.com\/dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.blogs.abeazam.com\/dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.blogs.abeazam.com\/dev\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.blogs.abeazam.com\/dev\/wp-json\/wp\/v2\/comments?post=389"}],"version-history":[{"count":10,"href":"http:\/\/www.blogs.abeazam.com\/dev\/wp-json\/wp\/v2\/posts\/389\/revisions"}],"predecessor-version":[{"id":434,"href":"http:\/\/www.blogs.abeazam.com\/dev\/wp-json\/wp\/v2\/posts\/389\/revisions\/434"}],"wp:attachment":[{"href":"http:\/\/www.blogs.abeazam.com\/dev\/wp-json\/wp\/v2\/media?parent=389"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.blogs.abeazam.com\/dev\/wp-json\/wp\/v2\/categories?post=389"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.blogs.abeazam.com\/dev\/wp-json\/wp\/v2\/tags?post=389"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}