10

I am working with Canvas.drawArc() in Android Studio and I have found the way to correctly draw the arc that I need, but I would like to know the coordinates of the Point() which actually create the Arc (not the edges but some of them in the middle). The code that I already have is:

Drawing the arc (works)

// Set the arc of movement of the encoder
public void setArc(Canvas canvas, Point startPoint, Point endPoint){
    Point centerArc = new Point((int) centerX, (int) centerY);
    Point leftEdge = new Point(startPoint.x, startPoint.y);
    Point rightEdge = new Point(endPoint.x, endPoint.y);

    int radiusArc = (int) Math.sqrt((leftEdge.x - centerArc.x)*(leftEdge.x - centerArc.x) + (leftEdge.y - centerArc.y)*(leftEdge.y - centerArc.y));

    int startAngle = (int) (190/Math.PI*atan2(leftEdge.y-centerArc.y, leftEdge.x-centerArc.x));
    int endAngle = (int) (210/Math.PI*atan2(rightEdge.y-centerArc.y, rightEdge.x-centerArc.y));

    RectF rect = new RectF(centerX - radiusArc, centerY - radiusArc, centerX + radiusArc, centerY + radiusArc);
    canvas.drawArc(rect, startAngle, endAngle, true, mRectPaint);
}

The problem is that, since Canvas.drawArc() is a void method, I am not sure how could I get these coordinates.

Any suggestion? Indeed, I am not even interested in drawing the Arc. I am just looking for a way to actually get those coordinates.

Maybe there is a way to create a curve within 3 points in java where I could get the coordinates. I would not mind using this method.

First approach

I have already tried to follow this answer but the values that I get are not the correct ones

//  Calculate the coordinates of 100 points of the arc
    Point[] coordinatesArc = new Point[100];
    coordinatesArc[0] = startPoint;
    Point coordinate = new Point();
    int xCoordinate;
    int yCoordinate;
    for (int i = 1; i<=98; i++){
        xCoordinate = startPoint.x + radiusArc*(int)Math.sin(i);
        yCoordinate = startPoint.y - radiusArc*(1-(int)Math.cos(i));
        coordinate.set(xCoordinate, yCoordinate);
        coordinatesArc[i]=coordinate;
    }
    coordinatesArc[99]= endPoint;
    Log.d(TAG, "Values: x = " + String.valueOf(coordinatesArc[97].x) + " y = " + String.valueOf(coordinatesArc[97].y) );

2nd approach

I have also checked Path from Android, but I not aware if it is possible to use it. It seems that couple of methods (arcTo and addArc) could help, but I do not know how to attach it to the canvas, so I guess it is not possible to combine them.

3rd approach

After finding another previous answer, I have tried to implement it but the coordinates are again, wrong (not even close to my endPoint).

Point centerArc = new Point((int) centerX, (int) centerY);
    Point leftEdge = new Point(startPoint.x, startPoint.y);
    int radiusArc = (int) Math.sqrt((leftEdge.x - centerArc.x)*(leftEdge.x - centerArc.x) + (leftEdge.y - centerArc.y)*(leftEdge.y - centerArc.y));
    int startAngle = (int) (190/Math.PI*atan2(leftEdge.y-centerArc.y, leftEdge.x-centerArc.x));

    Point[] coordinatesArc = new Point[100];
    Point auxPoint = new Point();
    coordinatesArc[0] = startPoint;
    for(int i = 1; i<=98;i++){
        auxPoint.x = (int) (centerX + radiusArc * Math.cos(startAngle + i));
        auxPoint.y = (int) (centerY + radiusArc * Math.sin(startAngle + i));
        coordinatesArc[i]= auxPoint;
    }
    coordinatesArc[99]= endPoint;
    Log.d(TAG, "COORDINATES ARC: x =  " + coordinatesArc[98].x  + " & y = " + coordinatesArc[98].y);
bellotas
  • 2,349
  • 8
  • 29
  • 60
  • Maybe this will help you: https://stackoverflow.com/questions/25935315/calculate-points-coordinates-of-an-arc – Joel Feb 24 '20 at 08:27
  • I would prefer to split the arc into 100 points rather than checking if a point is part of the arc. Do you know if it is possible? – bellotas Feb 24 '20 at 08:37

1 Answers1

7

Try the following using Path and PathMeasure.

This sample class draws on a custom view. The arc is drawn then twenty small circles are placed along the arc. You can divide the path into as many points as you like by dividing the path length. The array arcPoints will contain the selected points along the path.

If you don't want to draw the arc or the points, just delete the code that does the actual canvas drawing. The path will still be created and the points along the path captured.

enter image description here

MyView.java

 final Path mPath = new Path();

    int startAngle = (int) (190/Math.PI*atan2(startPoint.y-centerY, startPoint.x-centerX));
    int sweepAngle = (int) (210/Math.PI*atan2(endPoint.y-centerY, endPoint.x-centerX));
    int radiusArc = (int) Math.sqrt((startPoint.x - centerX)*(startPoint.x - centerX) + (startPoint.y - centerY)*(startPoint.y - centerY));

    final RectF oval = new RectF(centerX - radiusArc, centerY - radiusArc, centerX + radiusArc, centerY + radiusArc);

    mPath.addArc(oval, startAngle, sweepAngle);

    PathMeasure pm = new PathMeasure(mPath, false);
    float[] xyCoordinate = {startPoint.x, startPoint.y};
    float pathLength = pm.getLength();

    // Capture the points along the arc.
    PointF[] arcPoints = new PointF[20];
    for (int i = 0; i < 20; i++) {
        pm.getPosTan(pathLength * i / 19, xyCoordinate, null);
        arcPoints[i] = new PointF(xyCoordinate[0], xyCoordinate[1]);
    }

    Log.d(TAG, Arrays.toString(arcPoints));
    // Do drawing just to show the code works. Delete if drawing is not needed.
    canvas.drawPath(mPath, mRectPaint);
    for (int i = 0; i < 20; i++) {
        Log.d(TAG, String.format("Point #%d = (%.0f,%.0f)", i + 1, xyCoordinate[0], xyCoordinate[1]));
        canvas.drawCircle(arcPoints[i].x, arcPoints[i].y, 10, mTracerPaint); // Radius of the coordinate circle drawn.
    }
bellotas
  • 2,349
  • 8
  • 29
  • 60
Cheticamp
  • 61,413
  • 10
  • 78
  • 131
  • Hi, I am trying to implement your solution in my project but I am not able to make it work. It basically draws really huge areas in blue in my canvas, and not red line. I am gonna upload the solution within the code I have done. I believe that xyCoordinates are the coordinates x and y of my startPoint. Am I wrong? – bellotas Feb 28 '20 at 08:12
  • By the way, this code does not give me the coordinates of the points, It just draw them in the canvas. That's not what I am looking for – bellotas Feb 28 '20 at 08:15
  • @Mario If you remove the `canvas.drawPath()` statement, the code will not draw the path on the canvas but will still create the path. `xyCoordinates` will contains the points along the curve, but you will need to capture them in the for loop. The blue blob that you are seeing is because your are using the radius to draw the tracer circles. If you use just some value instead, such as "5", you should see what I posted. Anyway, all the drawing is just to demonstrate that the code works. You will just need to capture the point in the for loop and not do any of the drawing. – Cheticamp Feb 28 '20 at 12:38
  • Hi. I will have a look in couple of hours, or on Monday (depending on when do I finish something else). But thanks for the update. I ll have a look asap – bellotas Feb 28 '20 at 12:57
  • @Mario [Here](https://gist.github.com/Cheticamp/b4e92a39c759af9a83856603130abc3a) is a gist of the complete _MyView_ class. – Cheticamp Feb 28 '20 at 13:01
  • Thanks for the implementation. I have edited your answer so it matches better with my original question, and next Stackoverflow users will get a better answer (generating the RectF) – bellotas Mar 02 '20 at 08:03