Klevison
Klevison

Reputation: 3484

Draw a MKCircleRenderer on MKMapSnapshotter

I'm trying to draw a MKCircleRenderer in a MKMapSnapshotter.

So what I need: enter image description here

So what I have: enter image description here

My code:

+ (void)renderMapRegion:(MKCoordinateRegion)region
               withSize:(CGSize)size
             annotation:(MKAnnotationView *)annotation
         circleRenderer:(MKCircleRenderer *)circleRenderer
             completion:(CMMapViewRendererCallback)block
{
    MKMapSnapshotOptions *options = [MKMapSnapshotOptions new];
    options.region = region;
    options.scale = [UIScreen mainScreen].scale;
    options.size = size;

    MKMapSnapshotter *snapshotter = [[MKMapSnapshotter alloc] initWithOptions:options];

    [snapshotter startWithQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
              completionHandler:^(MKMapSnapshot *snapshot, NSError *error) {

                  if (error) {
                      block(nil, error);
                      return;
                  }

                  UIImage *image = snapshot.image;

                  UIGraphicsBeginImageContextWithOptions(image.size, YES, image.scale);
                  {
                      [image drawAtPoint:CGPointMake(0.0f, 0.0f)];
                      CGContextRef c = UIGraphicsGetCurrentContext();

                      if (circleRenderer.path) {
                          [circleRenderer applyFillPropertiesToContext:c atZoomScale:[UIScreen mainScreen].scale];
                          CGContextAddPath(c, circleRenderer.path);
                          CGContextFillPath(c);
                      }

                      CGRect rect = CGRectMake(0.0f, 0.0f, image.size.width, image.size.height);
                      CGPoint point = [snapshot pointForCoordinate:annotation.annotation.coordinate];
                      if (CGRectContainsPoint(rect, point)) {
                          point.x = point.x + annotation.centerOffset.x - (annotation.bounds.size.width / 2.0f);
                          point.y = point.y + annotation.centerOffset.y - (annotation.bounds.size.height / 2.0f);
                          [annotation.image drawAtPoint:point];
                      }

                      UIImage *compositeImage = UIGraphicsGetImageFromCurrentImageContext();
                      block(compositeImage,nil);
                  }

                  UIGraphicsEndImageContext();

              }];
}

My annotation is correct, but the MKCircleRenderer is drawn in a wrong coordinate.

UPDATE 1

After some tryings. I hade only one problem: correct radius size. My circle has 15meters radius value. But when I print on map has a 119 (I dont know about the unit)

private func renderMap(#placemark: CLPlacemark?, annotationView: MKAnnotationView) {
        self.tempPlaceMark = placemark
        let region = MKCoordinateRegionMakeWithDistance(annotationView.annotation.coordinate, 5000, 5000)
        let circle = MKCircle(centerCoordinate: annotationView.annotation.coordinate, radius: radius!)
        var render = MKCircleRenderer(circle: circle)
        render.fillColor = Color.YellowColor

        CMMapViewRenderer.renderMapRegion(region, withSize: self.mapView.frame.size, annotation: annotationView, circleRenderer: render) { (image: UIImage!, error: NSError!) -> Void in
            dispatch_async(dispatch_get_main_queue()) {
                if error == nil {
                    self.tempCoordinate = annotationView.annotation.coordinate
                    self.tempSnapshotImage = image
                }
                self.dismissProgress()
            }
        }
    }

enter image description here

Based on this solution: https://stackoverflow.com/a/8288467/846780

CGPoint circlePoint = [snapshot pointForCoordinate:annotation.annotation.coordinate];
CGRect boundingRect = [circleRenderer rectForMapRect:circleRenderer.circle.boundingMapRect];
CGFloat radius = boundingRect.size.width / 2;
CGContextSetStrokeColorWithColor(c, circleRenderer.fillColor.CGColor);
CGContextSetFillColorWithColor(c, circleRenderer.fillColor.CGColor);
CGContextSetLineWidth(c, 1);
CGContextSetShouldAntialias(c, YES);
CGContextAddArc(c, circlePoint.x, circlePoint.y, radius, 0, 2 * M_PI, true);
CGContextDrawPath(c, kCGPathFill);

Upvotes: 3

Views: 1013

Answers (1)

Rob
Rob

Reputation: 438232

Another approach is to draw this MKCircle yourself, converting the center and radius properties into coordinates within the view. This renders the circle within the current context (which I've used for adding MKCircle overlays to a snapshot image):

// use whatever colors you want

[[UIColor blueColor] setStroke];
[[[UIColor cyanColor] colorWithAlphaComponent:0.7] setFill];

// in my code, I'm iterating through the `overlays` objects, so I test to 
// see if it's a circle and cast appropriately

if ([overlay isKindOfClass:[MKCircle class]]) {
    CLLocationCoordinate2D coordinate = [(MKCircle *)overlay coordinate];
    CGPoint center = [snapshot pointForCoordinate:coordinate];
    CLLocationDistance radiusInMeters = [(MKCircle *)overlay radius];
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coordinate, radiusInMeters, 0);
    CGRect rect = [self.mapView convertRegion:region toRectToView:self.mapView];
    CGFloat radiusInPoints = rect.size.height;

    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radiusInPoints startAngle:0 endAngle:M_PI * 2.0 clockwise:TRUE];

    if (CGRectIntersectsRect([path bounds], CGRectMake(0, 0, image.size.width, image.size.height))) {
        [path stroke];
        [path fill];
    }
}

Upvotes: 1

Related Questions