Ios 使用图案图像在MKMapView上绘制线

Ios 使用图案图像在MKMapView上绘制线,ios,mkmapview,mkoverlay,Ios,Mkmapview,Mkoverlay,我尝试在带有图案图像的MKMapView上画一条线。 通过添加自定义的mkmappoverlay视图完成绘图 我能画出这条线,但似乎只使用图案图像最左边、最上面的像素,而不是整个图像 以下是我的绘图程序: void drawPatternCellCallback(void *info, CGContextRef cgContext) { UIImage *patternImage = [UIImage imageNamed:@"tmpLine"]; CGContextDrawIm

我尝试在带有图案图像的
MKMapView
上画一条线。 通过添加自定义的
mkmappoverlay
视图完成绘图

我能画出这条线,但似乎只使用图案图像最左边、最上面的像素,而不是整个图像

以下是我的绘图程序:

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);
    }
}
知道怎么了吗


塔克斯

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

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

代码稍微延迟一下,将几个覆盖添加到MKMapViews,给人一种动画的感觉

不是最漂亮的解决方案但它在实际操作中看起来相当不错:-)

/*启动动画*/
-(无效)plotRouteOnMap
{
[self.mapView removeOverlays:self.mapView.overlays];
//计算两个位置之间的位置数
self.points=[self-getPointsOnRouteFrom:
致:
onMapView:self.mapView];
[self addOverlysFromPointsWithStartFrom:[NSNumber numberWithInt:1]];
}
/*根据地图视图将CGPoint转换为CLLocation*/
-(CLLocation*)点到位置:(MKMapView*)mapView fromPoint:(CGPoint)fromPoint
{
CLLocationCoordinate2D坐标=[mapView convertPoint:fromPoint-toCoordinateFromView:mapView];
返回[[[CLLocation alloc]initWithLatitude:coord.latitude经度:coord.latitude]autorelease];
}
/*获取从到之间的位置对象列表*/
-(NSArray*)getPointsOnRouteFrom:(CLLocation*)from to:(CLLocation*)to onMapView:(MKMapView*)mapView
{
int NUMBER_OF_PIXELS_TO_SKIP=10;//数字越小,动画越流畅,但会产生更多层
NSMutableArray*ret=[NSMutableArray];
CGPoint fromPoint=[mapView convertCoordinate:from.coordinate toPointToView:mapView];
CGPoint toPoint=[mapView convertCoordinate:to.coordinate toPointToView:mapView];
NSArray*allPixels=[self-getAllPointsFromPoint:fromPoint-toPoint:toPoint];
对于(int i=0;i<[所有像素计数];i+=像素数{
NSValue*pointVal=[allPixels objectAtIndex:i];
[ret addObject:[self pointToLocation:mapView fromPoint:[pointVal CGPointValue]];
} 
[ret addObject:[self pointToLocation:mapView fromPoint:toPoint]];
返回ret;
}
/*计算从点到顶点的所有像素*/
-(NSArray*)GetAllPoints frompoint:(CGPoint)fPoint toPoint:(CGPoint)tPoint
{
/*Bresenham直线算法的简化实现*/
NSMutableArray*ret=[NSMutableArray];
浮动deltaX=fabsf(tPoint.x-fPoint.x);
浮点deltaY=fabsf(tPoint.y-fPoint.y);
浮点x=fPoint.x;
浮点y=fPoint.y;
浮动误差=deltaX deltaY;
浮动sx=-0.5;
浮动sy=-0.5;

如果(fPoint.xSwift接受答案的版本

使用mkoverlayrender将图像添加为覆盖

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")
        }
获取多段线中的坐标的步骤

    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
    }
func getLocationArrayFrom(startLocation:CLLocation,endLocation:CLLocation)->[CLLocationCoordinate2D]{
var CoordinateArray:[CLLocationCoordinate2D]=[]
如果let points=helperClass.getPointsOnRoute(from:startLocation,to:endLocation,on:mapView){
点对点{
设坐标=点坐标
坐标数组。追加(坐标)
}
}
返回坐标阵列
}
//马克:从电话线上取科迪酸盐
func getPointsOnRoute(从:CLLocation?,到:CLLocation?,在mapView:MKMapView?)->[CLLocation]{
让像素数跳过:Int=120
//数字越小,动画越平滑,但会产生更多层
var ret=[Any]()
var fromPoint:CGPoint?=nil
如果让A坐标=从?坐标{
fromPoint=mapView?转换(坐标、地形点到:mapView)
}
变量拓扑点:CGPoint?=nil
如果让A坐标=至?坐标{
toPoint=mapView?转换(坐标,Topointo:mapView)
}
让allPixels=getAllPoints(from:fromPoint!,to:toPoint!)
变量i=0
而我<(所有像素?.count){
设pointVal=allPixels![i]为?NSValue
ret.append(点(toLocation:mapView,from:(pointVal?.cgPointValue)!)
i+=要跳过的像素数
}
ret.append(点(toLocation:mapView,from:toPoint!))
返回ret as?[CLLocation]
}
/**根据地图视图将CGPoint转换为CLLocation*/
func point(toLocation mapView:MKMapView?,from from point:CGPoint)->CLLocation{
让坐标:CLLocationCoordinate2D?=mapView?转换(从点到坐标从:mapView)
返回CLLocation(纬度:坐标?.纬度0,经度:坐标?.经度0)
}
func getAllPoints(从fPoint:CGPoint到tPoint:CGPoint)->[任何]{
/*Bresenham直线算法的简化实现*/
var ret=[AnyHashable]()
设deltaX:Float=fabsf(Float(tPoint.x-fPoint.x))
设deltaY:Float=fabsf(Float(tPoint.y-fPoint.y))
变量x:Float=Float(fPoint.x)
变量y:Float=Float(fPoint.y)
var err:Float=deltaX-deltaY
变量sx:Float=-0.5
var-sy:Float=-0.5
如果fPoint.x-deltaY{
err-=deltaY
x+=sx
    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
    }