借鉴自定义MKOverlay

时间:2011-07-18 00:23:24

标签: iphone core-graphics mapkit overlay

我使用自定义MKOverlay通过MKMapView绘制天气数据。该图纸正在CoreGraphics中完成。对于这种特殊情况,仅仅在drawMapRect:zoomScale:inContext:方法中进行绘制是不够的,因为它处理平铺的方式。我需要立即绘制整个图像,而不是像drawMapRect方法那样平铺。

之前,我将雷达图像放在.gif中,所以我只是在其中添加了一个imageView,并在drawMapRect中调整了imageView框架的大小。

我的计划是做一些类似的事情。添加自定义UIView并在drawMapRect中调用setNeedsDisplay。

以下是相关代码。

MKOverlay对象的boundingMapRect属性:

- (MKMapRect)boundingMapRect
{
    CLLocationCoordinate2D upperLeftCoord = 
    CLLocationCoordinate2DMake(weatherData.radarArray.connectedRadar.latitude + 2.5,
                           weatherData.radarArray.connectedRadar.longitude - 2.5);

    MKMapPoint upperLeft = MKMapPointForCoordinate(upperLeftCoord);

    CLLocationCoordinate2D lowerRightCoord = 
    CLLocationCoordinate2DMake(weatherData.radarArray.connectedRadar.latitude - 2.5,
                           weatherData.radarArray.connectedRadar.longitude + 2.5);

    MKMapPoint lowerRight = MKMapPointForCoordinate(lowerRightCoord);

    double width = lowerRight.x - upperLeft.x;
    double height = lowerRight.y - upperLeft.y;

    MKMapRect bounds = MKMapRectMake(upperLeft.x, upperLeft.y, width, height);

    return bounds;
}

工作drawMapRect:zoomScale:inContext:代码(太慢了)。

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

    int numPaths = parser.dataPaths.size();

    // We have to pad the map rect a lot to allow for visibility testing that works well.
    MKMapRect testMapRect = MKMapRectMake(mapRect.origin.x - 40000, mapRect.origin.y - 40000, mapRect.size.width + 40000, mapRect.size.height + 40000);;

    // Only draw inside the area we are suppose to
    //CGRect rect = [self rectForMapRect:mapRect];
    //CGContextClipToRect(context, rect);

    // How see through is the radar data. 1 = opaque, 0 = completely transparent
    CGContextSetAlpha(context, 1);
    for (int i = 0; i < numPaths; i++) {
        // Make sure the bin is actually visible in this region before drawing it
        if (MKMapRectContainsPoint(testMapRect, parser.dataPaths[i]->points[0]) ||
            MKMapRectContainsPoint(testMapRect, parser.dataPaths[i]->points[1]) ||
            MKMapRectContainsPoint(testMapRect, parser.dataPaths[i]->points[2]) ||
            MKMapRectContainsPoint(testMapRect, parser.dataPaths[i]->points[3])) {
            CGMutablePathRef path = CGPathCreateMutable();
            CGPoint currentP = [self pointForMapPoint:parser.dataPaths[i]->points[0]];
            CGContextBeginPath(context);
            CGPathMoveToPoint(path, NULL, currentP.x, currentP.y);
            currentP = [self pointForMapPoint:parser.dataPaths[i]->points[1]];
            CGPathAddLineToPoint(path, NULL, currentP.x, currentP.y);
            currentP = [self pointForMapPoint:parser.dataPaths[i]->points[2]];
            CGPathAddLineToPoint(path, NULL, currentP.x, currentP.y);
            currentP = [self pointForMapPoint:parser.dataPaths[i]->points[3]];
            CGPathAddLineToPoint(path, NULL, currentP.x, currentP.y);
            currentP = [self pointForMapPoint:parser.dataPaths[i]->points[0]];
            CGPathAddLineToPoint(path, NULL, currentP.x, currentP.y);
            CGPathCloseSubpath(path);
            CGContextSetFillColorWithColor(context, colors[parser.dataPaths[i]->dataVal]);
            CGContextAddPath(context, path);
            CGContextFillPath(context);
            CGPathRelease(path);
        }
}

新的drawMapRect:zoomScale:inContext:code

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

    // We have to pad the map rect a lot to allow for visibility testing that works well.
    radarImageView.testMapRect = MKMapRectMake(mapRect.origin.x - 40000, mapRect.origin.y - 40000, mapRect.size.width + 40000, mapRect.size.height + 40000);

    radarImageView.frame = [self rectForMapRect:self.overlay.boundingMapRect];
    [radarImageView setNeedsDisplay];

}

自定义UIView的drawRect方法。

- (void)drawRect:(CGRect)rect {


    CGContextRef context = UIGraphicsGetCurrentContext();

    int numPaths = parser.dataPaths.size();

    CGContextSetAlpha(context, 1);
    for (int i = 0; i < numPaths; i++) {

        // Make sure the bin is actually visible in this region before drawing it
        if (MKMapRectContainsPoint(testMapRect, parser.dataPaths[i]->points[0]) ||
            MKMapRectContainsPoint(testMapRect, parser.dataPaths[i]->points[1]) ||
            MKMapRectContainsPoint(testMapRect, parser.dataPaths[i]->points[2]) ||
            MKMapRectContainsPoint(testMapRect, parser.dataPaths[i]->points[3])) {

            CGMutablePathRef path = CGPathCreateMutable();
            CGPoint currentP = [(RadarImageOverlayView *)self.superview pointForMapPoint:parser.dataPaths[i]->points[0]];

            CGContextBeginPath(context);
            CGPathMoveToPoint(path, NULL, currentP.x, currentP.y);

            currentP = [(RadarImageOverlayView *)self.superview pointForMapPoint:parser.dataPaths[i]->points[1]];
            CGPathAddLineToPoint(path, NULL, currentP.x, currentP.y);

            currentP = [(RadarImageOverlayView *)self.superview pointForMapPoint:parser.dataPaths[i]->points[2]];
            CGPathAddLineToPoint(path, NULL, currentP.x, currentP.y);

            currentP = [(RadarImageOverlayView *)self.superview pointForMapPoint:parser.dataPaths[i]->points[3]];
            CGPathAddLineToPoint(path, NULL, currentP.x, currentP.y);

            currentP = [(RadarImageOverlayView *)self.superview pointForMapPoint:parser.dataPaths[i]->points[0]];
            CGPathAddLineToPoint(path, NULL, currentP.x, currentP.y);

            CGPathCloseSubpath(path);
            CGContextSetFillColorWithColor(context, colors[parser.dataPaths[i]->dataVal]);
            CGContextAddPath(context, path);
            CGContextFillPath(context);
            CGPathRelease(path);
        }
    }
}

谢谢!

修改

我认为这个问题与RadarImageView的上下文有关。我在drawRect:方法中获取上下文的方式是否存在问题?

2 个答案:

答案 0 :(得分:3)

我建议您查看Apple的HazardMap示例。它有一些很好的例子来说明你正在做的事情。

KMLViewer也可能有所帮助!

答案 1 :(得分:2)

在调用drawMapRect之前,你不能准备你的路径吗?例如,当可见区域发生变化时。你只需要在drawMapRect中添加绘图上下文的路径。我想也许你甚至可以为给定的比例准备路径,然后在区域变化时平移和缩放上下文(CGContextScaleCTM)。

如果数据不经常更改。另一个优化是,一旦获得数据,就以较低的缩放级别为png格式准备图像。对于更高的缩放级别,您可以继续像您一样绘制。

要减少迭代次数,您可以使用平铺数据:而不是拥有一个包含所有数据的大数组,每个磁贴可以有一个数组。在第一步中,检索与当前可见区域相交的图块对应的数组,然后只在这些数组上循环。当然,这只适用于更高的缩放级别。

如果您不想进行优化,则可以在显示大量路径的情况下改善用户体验。要让用户在构建路径时与地图进行交互,您不应该在一个循环中处理所有元素。您可以一次处理1000个路径,然后使用performSelector:afterDelay:来延迟下一批处理。这样,您可以显示进度条并让用户与地图进行交互。