views:

359

answers:

3

UPDATE:

I'm still struggeling with this problem, although I may have some leads. Maybe it has something to do in what way the images are projected on the MKMapView, Google Maps uses the Mercator projection to project it's images onto a map.

alt text

If you compare the above image to that of the previous uploaded images, then it looks like the image is displayed on a Mercator projection while the image isn't. Can somebody help me any further with this problem?

UPDATE END

I'm currently working on a project which displays a rainfall radar over some part of the world. The radar image is provided by EUMETSTAT, they offer a KML file which can be loaded into Google Earth or Google Maps. If I load the KML file in Google Maps it displays perfectly, but if I draw the image using a MKOverlayView on a MKMapView, the image is slightly of.

For example, on the left side, Google Maps and on the right side the same image is displayed at a MKMapView.

alt text

alt text

The surface that the image covers can be viewed on Google Maps, the satellite that is used for the image is the "Meteosat 0 Degree" satellite.

The surface that both images cover is of the same size, this is the LatLonBox from the KML file, it specifies where the top, bottom, right, and left sides of a bounding box for the ground overlay are aligned.

  <LatLonBox id="GE_MET0D_VP-MPE-latlonbox">
        <north>57.4922</north>
        <south>-57.4922</south>
        <east>57.4922</east>
        <west>-57.4922</west>
        <rotation>0</rotation>
  </LatLonBox>

I create a new custom MKOverlay object called RadarOverlay with these parameters,

[[RadarOverlay alloc] initWithImageData:[[self.currentRadarData objectAtIndex:0] valueForKey:@"Image"] withLowerLeftCoordinate:CLLocationCoordinate2DMake(-57.4922, -57.4922) withUpperRightCoordinate:CLLocationCoordinate2DMake(57.4922, 57.4922)];

The implementation of the custom MKOverlay object; RadarOverlay

- (id) initWithImageData:(NSData*) imageData withLowerLeftCoordinate:(CLLocationCoordinate2D)lowerLeftCoordinate withUpperRightCoordinate:(CLLocationCoordinate2D)upperRightCoordinate
{
     self.radarData = imageData;

     MKMapPoint lowerLeft = MKMapPointForCoordinate(lowerLeftCoordinate);
     MKMapPoint upperRight = MKMapPointForCoordinate(upperRightCoordinate);

     mapRect = MKMapRectMake(lowerLeft.x, upperRight.y, upperRight.x - lowerLeft.x, lowerLeft.y - upperRight.y);

     return self;
}

- (CLLocationCoordinate2D)coordinate
{
     return MKCoordinateForMapPoint(MKMapPointMake(MKMapRectGetMidX(mapRect), MKMapRectGetMidY(mapRect)));
}

- (MKMapRect)boundingMapRect
{
     return mapRect;
}

The implementation of the custom MKOverlayView, RadarOverlayView

- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
    RadarOverlay* radarOverlay = (RadarOverlay*) self.overlay;

    UIImage *image          = [[UIImage alloc] initWithData:radarOverlay.radarData];

    CGImageRef imageReference = image.CGImage;

    MKMapRect theMapRect    = [self.overlay boundingMapRect];
   CGRect theRect           = [self rectForMapRect:theMapRect];
    CGRect clipRect     = [self rectForMapRect:mapRect];

    NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
    CGContextSetAlpha(context, [preferences floatForKey:@"RadarTransparency"]);

    CGContextAddRect(context, clipRect);
    CGContextClip(context);

    CGContextDrawImage(context, theRect, imageReference);

    [image release]; 
}

When I download the image, I flip the image so it can be easily drawn in the MKOverlayView

size_t width    = (CGImageGetWidth(imageReference) / self.scaleFactor);
size_t height   = (CGImageGetHeight(imageReference) / self.scaleFactor);

// Calculate colorspace for the specified image
CGColorSpaceRef imageColorSpace = CGImageGetColorSpace(imageReference);

// Allocate and clear memory for the data of the image
unsigned char *imageData = (unsigned char*) malloc(height * width * 4);
memset(imageData, 0, height * width * 4);

// Define the rect for the image
CGRect imageRect;
if(image.imageOrientation==UIImageOrientationUp || image.imageOrientation==UIImageOrientationDown) 
    imageRect = CGRectMake(0, 0, width, height); 
else 
    imageRect = CGRectMake(0, 0, height, width); 

// Create the imagecontext by defining the colorspace and the address of the location to store the data
CGContextRef imageContext = CGBitmapContextCreate(imageData, width, height, 8, width * 4, imageColorSpace, kCGImageAlphaPremultipliedLast);

CGContextSaveGState(imageContext);

// Scale the image to the opposite orientation so it can be easylier drawn with CGContectDrawImage
CGContextTranslateCTM(imageContext, 0, height);
CGContextScaleCTM(imageContext, 1.0, -1.0);

if(image.imageOrientation==UIImageOrientationLeft) 
{
    CGContextRotateCTM(imageContext, M_PI / 2);
    CGContextTranslateCTM(imageContext, 0, -width);
}
else if(image.imageOrientation==UIImageOrientationRight) 
{
    CGContextRotateCTM(imageContext, - M_PI / 2);
    CGContextTranslateCTM(imageContext, -height, 0);
} 
else if(image.imageOrientation==UIImageOrientationDown) 
{
    CGContextTranslateCTM(imageContext, width, height);
    CGContextRotateCTM(imageContext, M_PI);
}

// Draw the image in the context
CGContextDrawImage(imageContext, imageRect, imageReference);
CGContextRestoreGState(imageContext);

After I flipped the image, I manipulate it and then store it in memory as a NSData object.

It looks like the image got stretched, but it looks allright at the center of the image, which is at the equator.

A: 

Your image/overlay is most likely no longer proportional (i.e. it's been stretched). I've seen this kind of thing in my own app where the center of the view is correct, but as you go away from the equator toward either pole (top and bottom of screen) the map/overlay becomes increasingly distorted.

You are obviously scaling your image by scaleFactor. I'd take a look at that for starters.

size_t width    = (CGImageGetWidth(imageReference) / self.scaleFactor);
size_t height   = (CGImageGetHeight(imageReference) / self.scaleFactor);

Another good way to test your code to see if scaling is the culprit, is to scale your MKMapView down to the size of the overlay image. Leave the overlay image alone, and if it is no longer distorted then you know that is the problem.

Andrew
Thank you for your answer, the scale factor that I use for testing is always 1, so it won't be scaled by me, in this case I will comment out all the scaling code. I don't exactly understand what you mean by "is to scale your MKMapView down to the size of the overlay image", the overlay image itself is 2048x2048 pixels, but it needs to get stretched, see the Google Maps link for that. It only gets stretched in the wrong way. How did you solve it? I appreciate your help.
Jeroen de Leeuw
Either make the mkmapview 2048x2048. Or scale the image Down to say 320x320. Then make your mkmapview 320x320. I'm not sure why the image has to be stretched (I'm typing this on an iPod so I can't really follow that link right now).
Andrew
Changing the size of the MKMapView has no effect, the MKMapView is just a rectangle layed out over the world map which gets clipped. Changing the size will only change the rectangle, but is has no effect on the world map itself or on any annotations or overlays displayed on the world map. The surface of the MKOverlayView seems correct and it seems to correspond with the surface of the overlay on Google Maps, the only difference is the way it gets stretched.
Jeroen de Leeuw
Yes, but the MKRegion may cause it be stretched. Your latitude span, longitude span should match up with the width/height ratio of the MKMapView.
Andrew
I tried your solution, but it didn't work. http://dev.jeroendeleeuw.nl/image.png Do you have another solution, how did you solve it in your own project?
Jeroen de Leeuw
Jeroen, Did you ever figure this out?
Felix Khazin
A: 

Apple has a sample app from WWDC that parses KML and displays it on a map. If you are a paid developer you can access it from the WWDC videos page in iTunes. I recommend using their parser.

Cory Kilger
Another parser is the Simple-KML parser: http://github.com/incanus/Simple-KML
Dave DeLong
The parsing is not the problem, the problem is how you implement the parsed data on a MKOverlayView
Jeroen de Leeuw
And Apple's parser takes care of that.
Cory Kilger
It does not, not in the sample application "KMLViewer" as you suggested, but you put me in the right direction. The MKMapView uses Mercator projection, http://en.wikipedia.org/wiki/Mercator_projection, that's why the image is stretched that way. So the image has to be converted to use that projection, I think? Do you know how to do that?
Jeroen de Leeuw