I need LatLong coordinates in a RMAbstractMecatorWebSource subclasss,
I tried to pass the mapview to the sublcass to call pointToLatLong
method but the results were not always accurate, so I wrote the
following code.
//
// myTraficMapsSource.m
#import "myTraficMapsSource.h"
#import "RMFractalTileProjection.h"
CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI /
180;};
CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180/
M_PI;};
typedef struct {
CGPoint min;
CGPoint max;
} CGXYRect;
@implementation myTraficMapsSource
-(id) init
{
if (![super init])
return nil;
initialResolution = 2 * M_PI * 6378137 / [[self class]
tileSideLength];
//156543.03392804062 for sideLength 256 pixels
originShift = 2 * M_PI * 6378137 / 2.0;
// 20037508.342789244
return self;
}
-(NSString*) tileURL: (RMTile) tile
{
int sideLength = [[self class] tileSideLength];
RMLatLongBounds tileBounds = [self TileLatLonBounds:tile];
NSString *urlID = @"";//@"&id=1230918265386";
NSLog(@"%@ %s %f %f %f %f", [self class],_cmd,
tileBounds.northWest.longitude,tileBounds.southEast.latitude,tileBounds.southEast.longitude,tileBounds.northWest.latitude);
NSString *url = [NSString stringWithFormat:@"http://
mytrafic.beesurf.com/MapServer/SIM.aspx?CRS=EPSG:3785&BBOX=%f,%f,%f,
%f&WIDTH=%d&HEIGHT=%d
%@",tileBounds.northWest.longitude,tileBounds.southEast.latitude,tileBounds.southEast.longitude,tileBounds.northWest.latitude,sideLength,sideLength,urlID];
//NSLog(@"%@",url);
return url;
}
-(NSString*) description
{
return @"mytraficMaps";
}
// Converts given lat/lon in WGS84 Datum to XY in Spherical Mercator
EPSG:900913
-(CGPoint) LatLonToMeters: (CLLocationCoordinate2D) latlon
{
CGPoint meters;
meters.x = latlon.longitude * originShift / 180.0;
meters.y = (log( tan((90 + latlon.latitude) * M_PI / 360.0 )) /
(M_PI / 180.0)) * originShift / 180.0;
return meters;
}
//Resolution (meters/pixel) for given zoom level (measured at Equator)
-(float) ResolutionAtZoom : (int) zoom
{
return initialResolution /pow (2,zoom);
}
// Converts pixel coordinates in given zoom level of pyramid to EPSG:
900913
-(CGPoint) PixelsToMetersAtZoom: (int) px PixelY:(int)py atZoom:(int)
zoom
{
float resolution = [self ResolutionAtZoom: zoom];
CGPoint meters;
meters.x = px * resolution - originShift;
meters.y = py * resolution - originShift;
return meters;
}
//Converts XY point from Spherical Mercator EPSG:900913 to lat/lon in
WGS84 Datum
-(CLLocationCoordinate2D) MetersToLatLon: (CGPoint) meters
{
CLLocationCoordinate2D latlon;
latlon.longitude = (meters.x / originShift) * 180.0;
latlon.latitude = (meters.y / originShift) * 180.0;
latlon.latitude = - 180 /M_PI * (2 * atan( exp( latlon.latitude *
M_PI / 180.0)) - M_PI / 2.0);
return latlon;
}
//Returns bounds of the given tile in EPSG:900913 coordinates
-(CGXYRect) TileBounds: (RMTile) tile
{
int sideLength = [[self class] tileSideLength];
CGXYRect tileBounds;
tileBounds.min = [self PixelsToMetersAtZoom: (tile.x * sideLength)
PixelY:(tile.y * sideLength) atZoom: tile.zoom ];
tileBounds.max = [self PixelsToMetersAtZoom: ((tile.x+1) *
sideLength) PixelY: ((tile.y+1) * sideLength) atZoom:tile.zoom];
return tileBounds;
}
/* Returns bounds of the given tile in latutude/longitude using WGS84
datum
* returns a Rectangle2D with x = lon degrees , y = lat degrees,
* width=lonSpan, height=latSpan
* for an x,y,zoom as used by google.
*/
-(RMLatLongBounds) TileLatLonBounds: (RMTile) tile
{
CGXYRect tileBounds =[ self TileBounds: tile];
RMLatLongBounds result;
result.northWest = [self MetersToLatLon: tileBounds.min];
result.southEast = [self MetersToLatLon: tileBounds.max];
return result;
}
@end