50 votes

Comment tracer un arc entre deux points sur le canevas ?

J'ai deux points dans le canevas, je peux maintenant dessiner une ligne entre ces points comme dans l'image ci-dessous en utilisant

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

Je veux dessiner l'arc entre deux points comme dans l'image ci-dessous.

enter image description here

Comment puis-je dessiner comme cela ?

50voto

RajaReddy PolamReddy Points 9978

Finalement, j'ai obtenu la solution à partir de ce 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);

Pour calculer startAngle utilisez ce code :

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

Ici, point1 désigne l'endroit où vous souhaitez commencer à dessiner l'arc. sweepAngle désigne l'angle entre deux lignes. Nous devons calculer cet angle en utilisant deux points comme les points bleus dans l'image de ma question.

20voto

Adil Soomro Points 18868

Faites quelque chose comme ça :

//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);
}

7voto

j2emanue Points 3456

enter image description here Il faut d'abord visualiser les coordonnées en termes d'angles de départ et de balayage, puis cela deviendra plus clair.

Donc, si vous voulez juste la partie supérieure droite du cercle, nous pourrions faire quelque chose comme ça :

 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)

..

Il commence à 270 (selon le diagramme ci-dessus) et "balaie" de 90 degrés vers l'avant, ce qui donne cette forme :

enter image description here

Cette fois-ci, utilisons une valeur négative : nous voulons créer une demi-lune (arc) en partant du côté droit :

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

Ici, nous avons commencé à 0 et nous avons balayé -180 degrés. et les résultats sont les suivants :

enter image description here

4voto

Ahmad Baraka Points 110

J'ai essayé de faire quelque chose d'un peu différent et il s'agit de calculer les angles de balayage et de départ.

Je voulais montrer un arc qui représente le progrès sur un cercle qui va de haut en bas.

J'ai donc une valeur de progression de 0...100 et je veux afficher un arc qui commence de haut en bas pour remplir le cercle lorsque la progression est de 100.

Pour calculer l'angle de balayage, j'utilise :

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

Il faut ensuite calculer l'angle de départ

    int startAngle = 270 - sweepAngle / 2;

L'angle de départ est calculé de cette manière parce que :

  1. Il faut toujours commencer par le côté gauche, de haut en bas. L'angle de départ au sommet est donc égal à 270 (Notez qu'il va dans le sens des aiguilles d'une montre et que 0 = 3 heures, donc 12 heures est égal à 270 degrés).
  2. Ensuite, je veux calculer à quelle distance je vais m'éloigner de mon point de départ (270) et pour ce faire, je ne calcule que la moitié de l'angle de balayage parce que seule la moitié de l'arc sera sur le côté gauche et l'autre moitié sur le côté droit.

Si l'on considère que j'ai progressé de 25 %

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

Si vous souhaitez que la progression se fasse d'un autre côté (de gauche à droite, de droite à gauche, etc.), il vous suffira de remplacer 270 par le début de l'angle.

2voto

Hitesh Sahu Points 12561

Je suis peut-être en retard pour répondre, mais j'ai obtenu plus d'informations.

Après Android Lollipop Il y a deux façons d'aborder ce problème

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

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

Utilisation :

   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]);
    }

L'angle de balayage n'est rien d'autre que l'angle du secteur qui est dessiné dans le sens des aiguilles d'une montre.

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]);
    }
}

Le résultat sera le suivant

enter image description here

La même chose peut être obtenue en définissant des chemins et en itérant sur eux dans la méthode onDraw, comme illustré dans cet extrait :

 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;
    }

}

Code source complet :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X