How to draw Arc between two points on the Canvas?
Asked Answered
I

7

52

I have two points in the canvas, now I'm able to draw a line between those points like this below image by using

This code canvas.drawLine(p1.x, p1.y, p2.x, p2.y, paint); enter image description here

I want to draw the arc between two points like below image.

enter image description here

How can I draw like this.

Insatiate answered 21/6, 2012 at 5:24 Comment(9)
#4197249Scibert
@Scibert i tried that, but those functions are not available for canvas in android ..Insatiate
we have this function in android : drawArc(RectF, float, float, boolean, Paint);Insatiate
have you tried android-er.blogspot.in/2011/08/canvasdrawarc.html... you have to make oval shape on that positionScibert
@Scibert Your question (and your answer below) would be easier to understand if in the images above the blue dots would have labels p1 and p2.Pollack
I have summarized arc concept on my blog. I hope this will be helpful aniruddhambarakar.blogspot.in/2015/10/…Haines
Here is my solution for this problem : https://mcmap.net/q/354132/-android-path-addarc-in-canvas-between-two-pointsDneprodzerzhinsk
Here is my solution for this : https://mcmap.net/q/354132/-android-path-addarc-in-canvas-between-two-pointsDneprodzerzhinsk
only working for > api 21Inflect
I
52

Finally I got the solution from this code:

float radius = 20;
final RectF oval = new RectF();
oval.set(point1.x - radius, point1.y - radius, point1.x + radius, point1.y+ radius);
Path myPath = new Path();
myPath.arcTo(oval, startAngle, -(float) sweepAngle, true);

To calculate startAngle, use this code:

int startAngle = (int) (180 / Math.PI * Math.atan2(point.y - point1.y, point.x - point1.x));

Here, point1 means where you want to start drawing the Arc. sweepAngle means the angle between two lines. We have to calculate that by using two points like the blue points in my Question image.

Insatiate answered 23/6, 2012 at 9:26 Comment(10)
What does sweeep_angle mean?Honorarium
Here sweep_angle means the angle between two lines, we have to calculate that by using two points those are shortest points between the corner (i.e like point) like blue points in my Question image...Insatiate
HI @RajaReddyPolamReddy , How will I draw somthing in which lines will not appear, only arc will be shown.Soidisant
canvas.drawArc(.., .., false, ..) will draw arc without considering drawing of lines connected to its centers.Soidisant
@RajaReddy PolamReddy and what will be the "p1"?Dogcatcher
can you please post complete solution?Wigwag
Maybe yoy can give any advise for me about this question. #35845762Holbein
Do anyone know how to calculate sweep angle, we have three known points.Brianbriana
Calulated sweepAngle also: dist = Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); ; ; sweepAngle = 180- (dist/2)/radius; ; ; ;Brianbriana
All these methods are usually void, so they do not return anything but just drawing the arc itself. Do you know if it is possible to get, somehow, the coordinates of the points which form the arc?Rectangular
P
19

Do something like this:

//Initialized paint on a class level object.
Paint p = new Paint();
p.setColor(Color.BLACK);
//Calculate the rect / bounds of oval
RectF rectF = new RectF(50, 20, 100, 80);

@Override
protected void onDraw(Canvas canvas) {      
    //Do the drawing in onDraw() method of View.
    canvas.drawArc (rectF, 90, 45, false, p);
}
Pernickety answered 21/6, 2012 at 5:36 Comment(4)
Then you need to provide the start angle and sweep angle, see the docs herePernickety
the angle between the points will change dynamically and the position of those points also..Insatiate
How can I calculate the sweep angle? Could you please update the code to calculate this?Feeney
The 4th parameter to drawArc must be false, or otherwise it will draw a wedge. The Style also needs to be STROKE.Quinidine
C
9

enter image description herefirst we need to visual how the coordinates are in terms of start and sweep angels then it will become more clear.

so if you wanted just the right top piece of the circle, we could do something like this:

 val rect = RectF(0f, 0f, 500f, 300f)
        val paint = Paint()
        paint.apply {
            strokeWidth = 5f
            setStyle(Paint.Style.STROKE)
            color = COLOR.BLUE
        }
         path.addArc(rect, 270f, 90f)

..

this starts at 270 (per the diagram above and 'sweeps` 90 degrees forward. you then have this shape:

enter image description here

let's create one more so you get the hang of it. this time let's use a negative value: we want to create a semi half moon (arc) starting from the right side:

    path.addArc(rect, 0f, -180f)

here we started at 0 and 'sweeped` -180 degrees. and the results are:

enter image description here

Claybourne answered 6/10, 2019 at 6:48 Comment(0)
D
4

I was trying to do something a little different and it's all about calculating sweep and start angles.

I wanted to show an arc that represents progress on a circle that goes from top to bottom.

So I had progress value from 0...100 and I want to show an arc that start from top to bottom to fill the circle when the progress is 100.

To calculate the sweepAngle I use:

    int sweepAngle = (int) (360 * (getProgress() / 100.f));

Next is to calculate the startAngle

    int startAngle = 270 - sweepAngle / 2;

Start Angle is calculated this way because:

  1. It's always going to start from the left side, starting from the top to bottom. So starting angle at the top equals 270 (Note that it goes clockwise and 0 = 3 o'clock, so 12 o'clock equals 270 degrees)
  2. Next I want to calculate how far I'm going to get away from my starting point (270) and to do that I only calculate half of the sweep angle because only half of the arc will be on the left side and the other half on the right side.

So considering I have progress of 25%

sweepAngle = 90 degrees (90 degrees is quarter of a circle)
start angle = 225 (45 degrees away from 270)

If you want the progress to go from other sides (Left to right, right to left etc..) you will only need to replace 270 with the starting the angle.

Derrik answered 17/4, 2014 at 11:15 Comment(0)
E
2

I may be late to answer but I got more information.

After Android Lollipop there are two ways to address this problem

public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)

public void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)

Usage:

   RectF rectF = new RectF(left, top, right, bottom);

    // method 1
    canvas.drawArc (rectF, 90, 45, true,  paints[0]);

    // method 2
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        canvas.drawArc (left, top, right, bottom, 0, 45, true, paints[1]);
    }

Sweep angle is nothing more than angle of Sector which is drawn clockwise eg. for below code

private void drawArcs(Canvas canvas) {
    RectF rectF = new RectF(left, top, right, bottom);

    // white arc
    canvas.drawArc (rectF, 90, 45, true,  paints[0]);

    // Green arc
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        canvas.drawArc (left, top, right, bottom, 0, 45, true, paints[1]);
    }

    // Red stroked arc
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        canvas.drawArc (left, top, right, bottom, 180, 45, true,  paints[2]);
    }
}

Result will look like this

enter image description here

Same can be achieved with the help of defining Paths and then iterating over them in onDraw method as illustrated in this snippet:

 public class ArcDrawable extends Drawable {

    private int left, right, top, bottom;
    private  Paint[] paints = new Paint[3];
    private HashMap<Path, Paint> pathMap = new HashMap();


    public ArcDrawable() {

        // white paint
        Paint whitePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        whitePaint.setColor(Color.WHITE);
        paints[0]= whitePaint;

        // green paint
        Paint greenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        greenPaint.setColor(Color.GREEN);
        paints[1]= greenPaint;

        // red paint
        Paint redPaint =new Paint(Paint.ANTI_ALIAS_FLAG);
        redPaint.setColor(Color.RED);
        redPaint.setStyle(Paint.Style.STROKE);
        paints[2]= redPaint;
    }

    @Override
    public void draw(Canvas canvas) {

        //----------USE PATHS----------
        // Define and use custom  Path
        for (Map.Entry<Path, Paint> entry : pathMap.entrySet()) {
            // Draw Path on respective Paint style
            canvas.drawPath(entry.getKey(),  entry.getValue());

        }

        // -------OR use conventional Style---------
        //drawArcs(canvas);

    }


    //Same result
    private void drawArcs(Canvas canvas) {
        RectF rectF = new RectF(left, top, right, bottom);

        // method 1
        canvas.drawArc (rectF, 90, 45, true,  paints[0]);

        // method 2
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            canvas.drawArc (left, top, right, bottom, 0, 45, true, paints[1]);
        }

        // method two with stroke
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            canvas.drawArc (left, top, right, bottom, 180, 45, true,  paints[2]);
        }
    }


    @Override
    protected void onBoundsChange(Rect bounds) {
        super.onBoundsChange(bounds);

        int width = bounds.width();
        int height = bounds.height();

        left = bounds.left;
        right = bounds.right;
        top = bounds.top;
        bottom = bounds.bottom;

        final int size = Math.min(width, height);
        final int centerX = bounds.left + (width / 2);
        final int centerY = bounds.top + (height / 2);

        pathMap.clear();
        //update pathmap using new bounds
        recreatePathMap(size, centerX, centerY);
        invalidateSelf();
    }


    private Path recreatePathMap(int size, int centerX, int centerY) {

        RectF rectF = new RectF(left, top, right, bottom);

        // first arc
        Path arcPath = new Path();
        arcPath.moveTo(centerX,centerY);
        arcPath.arcTo (rectF, 90, 45);
        arcPath.close();
        // add to draw Map
        pathMap.put(arcPath, paints[0]);

        //second arc
        arcPath = new Path();
        arcPath.moveTo(centerX,centerY);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
          arcPath.arcTo (rectF, 0, 45);
        }
        arcPath.close();
        // add to draw Map
        pathMap.put(arcPath, paints[1]);

        // third arc
        arcPath = new Path();
        arcPath.moveTo(centerX,centerY);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            arcPath.arcTo (rectF, 180, 45);

        }
        arcPath.close();
        // add to draw Map
        pathMap.put(arcPath, paints[2]);

        return arcPath;

    }

    @Override
    public void setAlpha(int alpha) {

    }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {

    }

    @Override
    public int getOpacity() {
        return 0;
    }


}

Complete source code:

https://github.com/hiteshsahu/Arc-Drawable

Essential answered 18/3, 2019 at 11:17 Comment(0)
H
0

a sample for draw arc.

public static Bitmap clipRoundedCorner(Bitmap bitmap, float r, boolean tr, boolean tl, boolean bl, boolean br)
{
    int W = bitmap.getWidth();
    int H = bitmap.getHeight();

    if (r < 0)
        r = 0;

    int smallLeg = W;

    if(H < W )
        smallLeg = H;

    if (r > smallLeg)
        r = smallLeg / 2;

    float lineStop = r/2;

    Path path = new Path();
    path.moveTo(0,0);

    if(tr)
    {
        path.moveTo(0, lineStop);
        path.arcTo(new RectF(0,0, r,r), 180, 90, false);
    }

    path.lineTo(W-lineStop, 0);

    if(tl)
        path.arcTo(new RectF(W-r,0, W,r), 270, 90, false);
    else
        path.lineTo(W, 0);

    path.lineTo(W, H-lineStop);

    if(bl)
        path.arcTo(new RectF(W-r,H-r, W,H), 0, 90, false);
    else
        path.lineTo(W, H);

    path.lineTo(lineStop, H);

    if(br)
        path.arcTo(new RectF(0,H-r, r,H), 90, 90, false);
    else
        path.lineTo(0,H);

    if(tr)
        path.lineTo(0,lineStop);
    else
        path.lineTo(0,0);


    Bitmap output = Bitmap.createBitmap(W, H, Config.ARGB_8888);
    Canvas canvas = new Canvas(output);
    final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

    paint.setColor(Color.BLACK);
    canvas.drawPath(path, paint);

    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    canvas.drawBitmap(bitmap, 0, 0, paint);

    return output;
}
Heydon answered 28/7, 2017 at 19:19 Comment(0)
S
0

A simple solution was suggested here by Langkiller. This draws a cubic line from the start point via the control point to the end point.

Path path = new Path();
float startX = 0;
float startY = 2;
float controlX = 2;
float controlY = 4;
float endX = 4
float endY = 2
conePath.cubicTo(startX, startY, controlX, controlY,endX, endY);

Paint paint = new Paint();
paint.setARGB(200, 62, 90, 177);
paint.setStyle(Paint.Style.FILL);

canvas.drawPath(path, paint)
Slider answered 8/8, 2018 at 8:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.