2011-07-18 24 views
5

我正在使用自定義MKOverlay通過MKMapView繪製天氣數據。該繪圖正在CoreGraphics中完成。對於這種特殊情況,由於它處理平鋪的方式,在drawMapRect:zoomScale:inContext:方法中執行繪製是不夠的。我需要一次繪製整個圖像,而不是像drawMapRect方法那樣平鋪。在自定義MKOverlay上繪圖

之前,我有一個.gif的雷達圖像,所以我只是添加了一個imageView,並調整了drawMapRect中的imageView框的大小。

我的計劃是對此做類似的事情。在drawMapRect中添加一個自定義UIView並在其上調用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的:代碼

- (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

難道你不能在調用drawMapRect之前準備你的路徑。例如,當可見區域改變時。您只需在drawMapRect中添加繪圖上下文的路徑即可。您可能甚至可以爲給定的比例準備路徑,然後在區域更改時平移和縮放上下文(CGContextScaleCTM)。

如果數據不經常改變。另一個優化是在獲取數據後立即爲png格式準備較低縮放級別的圖像。對於更高的縮放級別,你可以像你一樣繼續繪製。

爲了減少迭代次數,您可以對數據使用平鋪:與每個數據塊都有一個大數組相比,您可以爲每個數據塊都有一個數組。在第一步中,您檢索與當前可見區域相交的瓦片對應的數組,然後您只會在這些數組上循環。當然,這隻適用於更高的縮放級別。

如果您不想優化,您可以改善顯示大量路徑的情況下的用戶體驗。爲了讓用戶在構建路徑時與地圖交互,不應該在一個循環中處理所有元素。您可以一次處理1000個路徑,然後使用performSelector:afterDelay:延遲下一批處理。這樣您就可以顯示進度條並讓用戶與地圖進行交互。

+0

啊這是個好主意。我會給它一個鏡頭,讓你知道它是如何工作的。 –

+0

我嘗試過這種方式,但表現仍然不夠好。典型的路徑數量約爲30,000。雷達域中的每個數據點都有一個路徑(零點不計算在內)。這個數字理論上可以達到165000. –

+0

路徑總數是多少?可見路徑的數量是多少?用戶可以更改縮放嗎?你能看到所有的路徑嗎? – FKDev

3

我建議看看蘋果的HazardMap樣本。它有一些很好的例子,可以完成你正在做的事情。

KMLViewer也可能有幫助!