Extra line when drawing an arc in swift

2019-06-09 08:50发布

问题:

I have this kind of code in a swift app and I get an extra greyed line reaching the starting point of the arc. The arc itself is drawn as expected, but it seems like CGContextMoveToPoint is leaving some trace behind before reaching the starting point.

override func drawRect(rect: CGRect) {
    var context:CGContextRef = UIGraphicsGetCurrentContext();

    var centerX,centerY,startAngle,endAngle,radius:CGFloat
     startAngle = CGFloat(M_PI_4)
    endAngle = -startAngle
    radius = (rect.height/2) / sin(startAngle)
    centerX = rect.width/2 + (radius*cos(startAngle))
    centerY = rect.height/2
    CGContextMoveToPoint(context, rect.width/2, rect.height)
    CGContextAddArc(context,centerX,centerY,radius,startAngle,endAngle,0);
    CGContextSetLineWidth(context, 3.0)
    CGContextSetStrokeColorWithColor(context, UIColor.lightGrayColor().CGColor)
    CGContextStrokePath(context)
}

Any idea of what might be wrong?

回答1:

This is a feature of CGContextAddArc. From the documentation:

If the current path already contains a subpath, Quartz adds a line connecting the current point to the starting point of the arc. If the current path is empty, Quartz creates a new new subpath with a starting point set to the starting point of the arc.

By moving to a point, you have established the starting point of the path. If you remove the CGContextMoveToPoint(), your arc will draw without the extra line.

Alternatively, you could move to the starting point of the arc:

CGContextMoveToPoint(context, centerX + radius*cos(startAngle), centerY + radius*sin(startAngle))

Update

(Editors note: I added this bit after @Michel figured out the problem. This is perhaps the answer I should have given after some discussion in the comments. It is provided here to perhaps help someone else in the future).

Your entire arc looks like the letter c, but only part of it is visible in the view (given the code above). The extra line is drawing from the middle of the bottom of the view to the lower start of the c curve which is offscreen.

If you want only the part of the arc that is in the view, then your starting angle should be 3 * M_PI_4 and your centerX calculation needs to then use - instead of +:

override func drawRect(rect: CGRect) {
    var context:CGContextRef = UIGraphicsGetCurrentContext();

    var centerX,centerY,startAngle,endAngle,radius:CGFloat
    startAngle = 3 * CGFloat(M_PI_4)
    endAngle = -startAngle
    radius = (rect.height/2) / sin(startAngle)
    centerX = rect.width/2 - (radius*cos(startAngle))
    centerY = rect.height/2
    CGContextMoveToPoint(context, rect.width/2, rect.height)
    CGContextAddArc(context,centerX,centerY,radius,startAngle,endAngle,0);
    CGContextSetLineWidth(context, 3.0)
    CGContextSetStrokeColorWithColor(context, UIColor.lightGrayColor().CGColor)
    CGContextStrokePath(context)
}

Then, your starting point will be in the view and no extra line will appear.