Нанесение на заказ МКОверлай - PullRequest
5 голосов
/ 18 июля 2011

Я использую пользовательский MKOverlay для рисования данных о погоде через MKMapView.Рисование выполняется в CoreGraphics.Для этого конкретного случая недостаточно рисовать в drawMapRect: zoomScale: inContext: метод из-за того, как он обрабатывает мозаику.Мне нужно, чтобы изображение целиком отображалось сразу, а не мозаично, как метод drawMapRect.

Раньше у меня было изображение радара в .gif, поэтому я просто добавил к нему imageView и изменил размер кадра imageView в drawMapRect.

Мой план состоял в том, чтобы сделать что-то подобное с этим.Добавьте пользовательский UIView и вызовите setNeedsDisplay для него в drawMapRect.

Вот соответствующий код.

Свойство boundingMapRect объекта 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;
}

Рабочий 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];

}

Метод drawRect пользовательского UIView.

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

3 голосов
/ 24 июля 2011

Предлагаю взглянуть на образец HazardMap от Apple. Здесь есть несколько хороших примеров того, что вы делаете.

KMLViewer также может помочь!

2 голосов
/ 27 июля 2011

Не могли бы вы подготовить свой путь (и) до вызова drawMapRect. Например, когда видимая область изменяется. Вам просто нужно добавить путь к контексту рисования в drawMapRect. Я думаю, что вы могли бы даже подготовить пути для заданного масштаба, а затем панорамировать и масштабировать контекст (CGContextScaleCTM) при изменении региона.

Если данные меняются не часто. Другой оптимизацией будет подготовка изображений в формате png для более низкого уровня масштабирования, как только вы получите данные. Для более высокого уровня масштабирования вы можете продолжать рисовать так же, как и вы.

Чтобы уменьшить количество итераций, вы можете использовать мозаику с вашими данными: вместо одного большого массива со всеми вашими данными, вы можете иметь один массив для каждой плитки. На первом этапе вы извлекаете массивы, соответствующие плитке, пересекающей текущую видимую область, а затем вы будете зацикливаться только на этих массивах. Конечно, это будет работать только для более высокого уровня масштабирования.

Если вы не хотите оптимизировать, вы можете улучшить взаимодействие с пользователем в тех случаях, когда отображается много путей. Чтобы позволить пользователю взаимодействовать с картой при построении путей, вам не следует обрабатывать все элементы в одном цикле. Вы можете обрабатывать 1000 путей одновременно, а затем использовать executeSelector: afterDelay: для отсрочки обработки следующего пакета. Таким образом, вы можете отобразить индикатор выполнения и позволить пользователю взаимодействовать с картой.

...