在MKMapView上绘制图案线条

3

我试图在MKMapView上使用图案图像绘制一条线。 通过添加自定义的MKMapOverlay视图进行绘制。

我能够画出线,但似乎只使用了图案图像的左上角像素进行绘制,而不是整个图像。

这是我的绘图例程:

void drawPatternCellCallback(void *info, CGContextRef cgContext)
{
    UIImage *patternImage = [UIImage imageNamed:@"tmpLine"];
    CGContextDrawImage(cgContext, CGRectMake(0, 0, patternImage.size.width, patternImage.size.height), patternImage.CGImage);

}

- (void)drawMapRect:(MKMapRect)mapRect
          zoomScale:(MKZoomScale)zoomScale
          inContext:(CGContextRef)context
{
    float alpha = 1;        
    float tileW = 6.0f;
    float tileH = 4.0f;
    CGFloat lineWidth = MKRoadWidthAtZoomScale(zoomScale)*2;
    CGMutablePathRef path = CGPathCreateMutable();


    if (path != nil)

    {
        //setup styles
        CGContextSetRGBStrokeColor(context, 0.0f, 0.0f, 1.0f, 0.5f);

        const CGPatternCallbacks kPatternCallbacks = {0, drawPatternCellCallback, NULL};
        CGPatternRef strokePattern = CGPatternCreate(
                                                     NULL,
                                                     CGRectMake(0, 0, tileW, tileH), 
                                                     CGAffineTransformIdentity,
                                                     tileW, // horizontal spacing
                                                     tileH,// vertical spacing
                                                     kCGPatternTilingConstantSpacing,
                                                     true,
                                                     &kPatternCallbacks);
        //color sapce
        CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
        CGContextSetStrokeColorSpace(context, patternSpace);

        //pattern
        CGContextSetStrokePattern(context, strokePattern, &alpha);

        //joins/ends
        CGContextSetLineJoin(context, kCGLineJoinMiter);
        CGContextSetLineCap(context, kCGLineCapButt);
        CGContextSetLineWidth(context, lineWidth);

        //OK, let's draw it
        CGPoint firstCGPoint = [self pointForMapPoint:self.point1];    
        CGPoint lastCGPoint = [self pointForMapPoint:self.point2];
        CGPathMoveToPoint(path, NULL, lastCGPoint.x, lastCGPoint.y);    
        CGPathAddLineToPoint(path, NULL, firstCGPoint.x, firstCGPoint.y);
        CGContextAddPath(context, path);
        CGContextStrokePath(context);

        //house hold
        CGPathRelease(path);
        CGPatternRelease(strokePattern);
        CGColorSpaceRelease(patternSpace);
    }
}

有什么问题吗?

谢谢!

2个回答

6

我最终采用了完全不同的策略。 现在,我不再添加自己的覆盖层,而是依赖于MKPolyLine

使用以下代码,我能够在MKMapView上从点A到点B添加一个伪动画线。

代码向MKMapViews添加了几个覆盖层,并稍微延迟一下,给人以动画效果的印象。

虽然不是最美的解决方案!- 但实际效果看起来相当不错 :-)

/*start the animation*/
-(void)plotRouteOnMap
{
    [self.mapView removeOverlays:self.mapView.overlays];
    //calculate a number locations between the two locations
    self.points = [self getPointsOnRouteFrom:<FROM_LOCATION>
                                          to:<TO_LOCATION>
                                   onMapView:self.mapView]; 
    [self addOverlaysFromPointsWithStartFrom:[NSNumber numberWithInt:1]];
}

/*convert a CGPoint to a CLLocation according to a mapView*/
- (CLLocation*)pointToLocation:(MKMapView *)mapView fromPoint:(CGPoint)fromPoint
{
    CLLocationCoordinate2D coord = [mapView convertPoint:fromPoint toCoordinateFromView:mapView];
    return [[[CLLocation alloc] initWithLatitude:coord.latitude longitude:coord.longitude] autorelease];
}

/*get a list of Location objects between from and to*/
-(NSArray*)getPointsOnRouteFrom:(CLLocation*)from to:(CLLocation*)to onMapView:(MKMapView*)mapView
{
    int NUMBER_OF_PIXELS_TO_SKIP =10; //lower number will give a more smooth animation, but will result in more layers 
    NSMutableArray *ret = [NSMutableArray array];
    CGPoint fromPoint = [mapView convertCoordinate:from.coordinate toPointToView:mapView];
    CGPoint toPoint = [mapView convertCoordinate:to.coordinate toPointToView:mapView];

    NSArray *allPixels = [self getAllPointsFromPoint:fromPoint toPoint:toPoint];
    for (int i = 0 ; i < [allPixels count] ; i+=NUMBER_OF_PIXELS_TO_SKIP) {
        NSValue *pointVal = [allPixels objectAtIndex:i];
        [ret addObject:[self pointToLocation:mapView fromPoint:[pointVal CGPointValue]]];  
    } 
    [ret addObject:[self pointToLocation:mapView fromPoint:toPoint]];  
    return ret;
}

/*calulate alle pixels from point to toPint*/
-(NSArray*)getAllPointsFromPoint:(CGPoint)fPoint toPoint:(CGPoint)tPoint
{
    /*Simplyfied implementation of Bresenham's line algoritme */
    NSMutableArray *ret = [NSMutableArray array];
    float deltaX = fabsf(tPoint.x - fPoint.x);
    float deltaY = fabsf(tPoint.y - fPoint.y);
    float x = fPoint.x;
    float y = fPoint.y;
    float err = deltaX-deltaY;

    float sx = -0.5;
    float sy = -0.5;
    if(fPoint.x<tPoint.x)
        sx = 0.5;

    if(fPoint.y<tPoint.y)
        sy = 0.5;
    do {
        [ret addObject:[NSValue valueWithCGPoint:CGPointMake(x, y)]];
        float e = 2*err;
        if(e > -deltaY)
        {
            err -=deltaY;
            x +=sx; 
        }
        if(e < deltaX)
        {
            err +=deltaX;
            y+=sy;
        }
    } while (round(x)  != round(tPoint.x) && round(y) != round(tPoint.y));
    [ret addObject:[NSValue valueWithCGPoint:tPoint]];//add final point
    return ret;

}

/*add a poly line overlay to mapview which start at position 0 and end in 'end' in the array points*/
-(void)addOverlaysFromPointsWithStartFrom:(NSNumber*)end
{
    int intEnd = [end intValue];

    //construct polyline view from start
    CLLocationCoordinate2D *locations = malloc(sizeof(CLLocationCoordinate2D)*2); 
    CLLocation *loc1 = (CLLocation*)[points objectAtIndex:0];
    CLLocation *loc2= (CLLocation*)[points objectAtIndex:intEnd];
    locations[0] = loc1.coordinate;
    locations[1] = loc2.coordinate;
    MKPolyline *line = [MKPolyline polylineWithCoordinates:locations count:2]; 
    [self.mapView addOverlay:line];


    if((intEnd+1) < [points count])//add more overlays after delays unless this is the endpoint
    {        
        [self performSelector:@selector(addOverlaysFromPointsWithStartFrom:) withObject:[NSNumber numberWithInt:intEnd + 1] afterDelay:0.01];
    }

}

当您缩放地图时会发生什么! - turtle
MKPolyLine不会被缩放,但是每个点之间的距离会增加。您可以在此应用程序中查看其效果:https://itunes.apple.com/us/app/city-distance/id561422939?mt=8 - EsbenB
应用程序看起来不错。但是根据上面粘贴的代码,当你缩放地图时,points 的计数会变得比 intEnd 更多。为什么会发生这种情况,你将如何处理它。CLLocation *loc2= (CLLocation*)[points objectAtIndex:intEnd]; 导致了崩溃! - turtle

2

以下是接受答案的Swift版本:

使用MKOverlayRenderer添加图像叠加

func addLayersOfAnimatingOverlay() {
        let sourcePoint = // enter as CLLocation
        let destinationPoint =  // enter as CLLocation
        let pointsCoordinatesArray = self.getLocationArrayFrom(startLocation: sourcePoint, endLocation: destinationPoint)
            //add overlay on above coordinates
        DispatchQueue.main.async{
            self.addDirectionOverlayInMap(locationArray: self.pointsCoordinates1, title: "1")
        }

获取MKPolyline中的坐标
    func getLocationArrayFrom(startLocation: CLLocation, endLocation: CLLocation) -> [CLLocationCoordinate2D] {
            var coordinatesArray: [CLLocationCoordinate2D] = []
            if let points = helperClass.getPointsOnRoute(from: startLocation, to: endLocation, on: mapView) {
                for point in points {
                    let coordinate  = point.coordinate
                    coordinatesArray.append(coordinate)
                }
            }
            return coordinatesArray
        }

    //MARK: get cordinates from line
        func getPointsOnRoute(from: CLLocation?, to: CLLocation?, on mapView: MKMapView?) -> [CLLocation]? {
            let NUMBER_OF_PIXELS_TO_SKIP: Int = 120
            //lower number will give a more smooth animation, but will result in more layers
            var ret = [Any]()

            var fromPoint: CGPoint? = nil
            if let aCoordinate = from?.coordinate {
                fromPoint = mapView?.convert(aCoordinate, toPointTo: mapView)
            }
            var toPoint: CGPoint? = nil
            if let aCoordinate = to?.coordinate {
                toPoint = mapView?.convert(aCoordinate, toPointTo: mapView)
            }
            let allPixels = getAllPoints(from: fromPoint!, to: toPoint!)
            var i = 0
            while i < (allPixels?.count)! {
                let pointVal = allPixels![i] as? NSValue
                ret.append(point(toLocation: mapView, from: (pointVal?.cgPointValue)!)!)
                i += NUMBER_OF_PIXELS_TO_SKIP
            }
            ret.append(point(toLocation: mapView, from: toPoint!)!)
            return ret as? [CLLocation]
        }

/**convert a CGPoint to a CLLocation according to a mapView*/
    func point(toLocation mapView: MKMapView?, from fromPoint: CGPoint) -> CLLocation? {
        let coord: CLLocationCoordinate2D? = mapView?.convert(fromPoint, toCoordinateFrom: mapView)
        return CLLocation(latitude: coord?.latitude ?? 0, longitude: coord?.longitude ?? 0)
    }

    func getAllPoints(from fPoint: CGPoint, to tPoint: CGPoint) -> [Any]? {
        /*Simplyfied implementation of Bresenham's line algoritme */
        var ret = [AnyHashable]()
        let deltaX: Float = fabsf(Float(tPoint.x - fPoint.x))
        let deltaY: Float = fabsf(Float(tPoint.y - fPoint.y))
        var x: Float = Float(fPoint.x)
        var y: Float = Float(fPoint.y)
        var err: Float = deltaX - deltaY
        var sx: Float = -0.5
        var sy: Float = -0.5
        if fPoint.x < tPoint.x {
            sx = 0.5
        }
        if fPoint.y < tPoint.y {
            sy = 0.5
        }
        repeat {
            ret.append(NSValue(cgPoint: CGPoint(x: CGFloat(x), y: CGFloat(y))))
            let e: Float = 2 * err
            if e > -deltaY {
                err -= deltaY
                x += sx
            }
            if e < deltaX {
                err += deltaX
                y += sy
            }
        } while round(Float(x)) != round(Float(tPoint.x)) && round(Float(y)) != round(Float(tPoint.y))
        ret.append(NSValue(cgPoint: tPoint))
        //add final point
        return ret
    }

这会产生以下效果(不含动画) enter image description here

该项目可以在这里找到。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接