Dan
Dan

Reputation: 641

iOS 7 - Drawing a set of coords on MapKit with MKOverlayRenderer

I am trying to take a set of GPS coordinates and draw them onto an overlay using a custom MKOverlay and MKOverlayRenderer. I haven't been able to get the points to show. I know it might not be necessary do this in this way but this is the first step of a more complex overlay.

Code in the overlayrenderer here. The points array holds NSValue objects which hold my MKMapPoint structs. I've confirmed those MKMapPoints are correct inside of the for loop.

-(instancetype)initWithOverlay:(Heatmap*)overlay {
    self = [super initWithOverlay:overlay];
    if (self){
        self.points = overlay.testCoordinates;
    }
    return self;
}

- (void)drawMapRect:(MKMapRect)mapRect
          zoomScale:(MKZoomScale)zoomScale
          inContext:(CGContextRef)context
{

    CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);

    for (NSValue *point in self.points){
        MKMapPoint mapPoint;
        [point getValue:&mapPoint];
        CGPoint datpoint = [self pointForMapPoint:mapPoint];
        CGRect rect = CGRectMake(datpoint.x/zoomScale, datpoint.y/zoomScale, 1.0/zoomScale, 1.0/zoomScale);
        CGContextFillRect(context, rect);
    }

In the view controller that is my MapView delegate:

- (void)viewDidLoad
{
    Heatmap *heatmap = [[Heatmap alloc] init];
    [self.mapView setVisibleMapRect:heatmap.boundingMapRect];
    [self.mapView addOverlay:heatmap];
}

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
    HeatmapOverlayRenderer *renderer = [[HeatmapOverlayRenderer alloc] initWithOverlay:overlay];
    return renderer;
}

The boundingMapRect is set correctly. So the app should load and I should see 100 points within the screen bounds. Any idea what I might have wrong? This is all new to me.

Upvotes: 3

Views: 1819

Answers (1)

user467105
user467105

Reputation:

In drawMapRect, this line is probably the cause of the point rects not showing:

CGRect rect = CGRectMake(datpoint.x/zoomScale, datpoint.y/zoomScale, 
                           1.0/zoomScale, 1.0/zoomScale);

You probably do not want to change the position of the point's rect based on the zoomScale.
The rect's apparent position based on the zoom will be done automatically by the map view.

The current code is changing its absolute position and size on the map based on the zoom.
The resulting position is most likely not on the map.

Instead, draw the point's rect without any scaling.

However, to calculate the right width to use in CGPoints (from meters), you need to do some calculation:

for (NSValue *point in self.points)
{
    MKMapPoint mapPoint;
    [point getValue:&mapPoint];

    CGPoint datpoint = [self pointForMapPoint:mapPoint];


    CLLocationDistance rectWidthMeters = 100000.0;
    //above sets rect width to 100 km, adjust as needed

    CLLocationCoordinate2D mpc = MKCoordinateForMapPoint(mapPoint);

    double rectWidthMapPoints = MKMapPointsPerMeterAtLatitude(mpc.latitude);

    MKMapPoint mpRight = 
      MKMapPointMake (mapPoint.x + (rectWidthMapPoints * rectWidthMeters), 
                      mapPoint.y);

    CGPoint datpointRight = [self pointForMapPoint:mpRight];

    CGFloat rectWidth = datpointRight.x - datpoint.x;


    CGRect rect = CGRectMake(datpoint.x, datpoint.y, rectWidth, rectWidth);

    CGContextFillRect(context, rect);
}

Make sure you are zoomed in enough at the right location to see the squares.


You may be interested in looking at Apple's sample app HazardMap which demonstrates something similar showing color-coded earthquake hazard levels based on a grid of locations.

Upvotes: 0

Related Questions