2011-07-18 7 views
5

Estoy usando una MKOverlay personalizada para dibujar datos meteorológicos sobre un MKMapView. El dibujo se está haciendo en CoreGraphics. Para este caso particular, no es suficiente hacer el dibujo en el método drawMapRect: zoomScale: inContext: debido a cómo maneja el mosaico. Necesito que la imagen completa se dibuje de una vez en vez de mosaico como el método drawMapRect.Dibujo en MKOverlay personalizado

Antes, tenía la imagen de radar en un archivo .gif así que acabo de agregarle un imageView y cambiar el tamaño del marco de imageView en drawMapRect.

Mi plan era hacer algo similar con esto. Agregue una UIView personalizada y llame a setNeedsDisplay sobre ella en drawMapRect.

Aquí está el código relevante.

La propiedad boundingMapRect del objeto MKOverlay:

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

El drawMapRect de trabajo: zoomScale: InContext: código (que es demasiado lento).

- (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); 
     } 
} 

El nuevo drawMapRect: zoomScale: InContext: Código

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

} 

El método drawRect de la UIView personalizado.

- (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); 
     } 
    } 
} 

Gracias!

EDITAR

Pienso que el problema tiene que ver con el contexto de la RadarImageView. ¿Hay algún problema con la forma en que obtengo el contexto en el método drawRect: tal vez?

Respuesta

2

¿No pudo preparar su (s) ruta (s) antes de llamar a drawMapRect? Por ejemplo, cuando la región visible cambia. Simplemente tendría que agregar la ruta al contexto del dibujo en drawMapRect. Creo que tal vez podría incluso preparar las rutas para una escala determinada y luego hacer un recorrido panorámico y escalar el contexto (CGContextScaleCTM) cuando la región cambie.

Si los datos no cambian con frecuencia. Otra optimización sería preparar imágenes en formato png para el nivel de zoom más bajo tan pronto como obtenga los datos. Para un mayor nivel de zoom, puede continuar dibujando como lo hace.

Para reducir el número de iteraciones, puede usar el mosaico con sus datos: en lugar de tener una gran matriz con todos sus datos, podría tener una matriz para cada mosaico. En un primer paso, recuperas las matrices correspondientes a la tesela que intersecta la región visible actual y luego haces un bucle solo en estas matrices. Por supuesto, eso solo funcionaría para un mayor nivel de zoom.

Si no desea optimizar, puede mejorar la experiencia del usuario para los casos en que se muestran muchas rutas. Para permitir que el usuario interactúe con el mapa mientras construye las rutas, no debe procesar todos los elementos en un bucle. Puede procesar 1000 rutas a la vez y luego utilizar performSelector: afterDelay: para retrasar el procesamiento del siguiente lote. De esta forma, puede mostrar una barra de progreso y permitir que el usuario interactúe con el mapa.

+0

Ahh esta es una buena idea. Le daré una oportunidad y le dejaré saber cómo funciona. –

+0

Intenté esto y el rendimiento aún no era lo suficientemente bueno. El número típico de rutas es de alrededor de 30,000. Hay una ruta para cada punto de datos en el dominio del radar (los ceros no se cuentan). En teoría, este número podría llegar a 165000. –

+0

¿Cuál es el número total de rutas? ¿Cuál es el número de caminos visibles? ¿Puede el usuario cambiar el zoom? ¿Puedes tener todos los caminos visibles? – FKDev

3

Sugiero echar un vistazo a la muestra HazardMap de Apple. Tiene algunos buenos ejemplos de hacer exactamente lo que buscas.

¡El KMLViewer también puede ayudarnos!