Skip to content Skip to sidebar Skip to footer

Canvas.drawArc() Artefacts

I draw an arc on canvas in a custom view as shown below. Paint and rectangle are defined outside of onDraw() and added in there for simplicity purpose. protected void onDraw(Canvas

Solution 1:

I'm a StackOverflow newbie, wanted to add a comment but could not (having insufficient points) so had to put my comment in an answer !

One strange thing is that the arc overshoots the specified end position with a straight vertical line at the outer side. The inner end point seems to be ok. Of course this and the other mess of lines does not tell what causes the problem.

It seems to appear when the end angle is at exactly a multiple of 90 degrees. This looks like a numeric calculation bug, float round-off issue etc. @kcoppock remarked that 314.98f already circumvents the bug. Probably any value other than exactly 315.0f may do the trick.

If code optimization is involved (attempts to draw the arc in as little line segments as possible) another trick that may work is to simplify the arc by cutting it into pieces -> use multiple drawArc calls that each span a certain maximum angle. Candidates are 30, 45, 90 and 180 degrees. Remains to be seen if the joints will be invisible...

It's a bit of a long shot, hope any of these suggestions might work.


Solution 2:

I've found the solution! :)

Instead of this:

RectF rectangle = new RectF(60f, 60f, 480f, 480f);

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(0x40000000);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(120);

canvas.drawArc(rectangle, 225f, 315f, false, paint);

Use this:

RectF rectangle = new RectF(60f, 60f, 480f, 480f);

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(0x40000000);
paint.setStyle(Paint.Style.FILL);

float strokeWidth = 120;
float startAngle = 225f;
float sweepAngle = 315f;

RectF pathRect = new RectF();
Path path = new Path();
float s = strokeWidth / 2;
pathRect.left = rectangle.left - s;
pathRect.right = rectangle.right + s;
pathRect.top = rectangle.top - s;
pathRect.bottom = rectangle.bottom + s;
path.arcTo(pathRect, startAngle, sweepAngle);
pathRect.left = rectangle.left + s;
pathRect.right = rectangle.right - s;
pathRect.top = rectangle.top + s;
pathRect.bottom = rectangle.bottom - s;
path.arcTo(pathRect, startAngle + sweepAngle, -sweepAngle);
path.close();
canvas.drawPath(path, paint);

This code results in slower run, but it doesn't produce artefacts. :)


Post a Comment for "Canvas.drawArc() Artefacts"