如何在画布上的两点之间绘制圆弧?

时间:2012-06-21 05:24:20

标签: android android-canvas ondraw

我在画布上有两个点,现在我可以使用

在这些点之间绘制一条线,如下图所示

此代码canvas.drawLine(p1.x, p1.y, p2.x, p2.y, paint); enter image description here

我想在两个点之间绘制弧线,如下图所示。

enter image description here

我怎么画这样。

7 个答案:

答案 0 :(得分:46)

最后我从这段代码中得到了解决方案:

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

要计算startAngle,请使用以下代码:

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

此处,point1表示您要开始绘制Arc的位置。 sweepAngle表示两条线之间的角度。我们必须通过使用两个点来计算它,比如我的问题图像中的蓝点。

答案 1 :(得分:18)

做这样的事情:

@Override
protected void onDraw(Canvas canvas) {      
    Paint p = new Paint();
    RectF rectF = new RectF(50, 20, 100, 80);
    p.setColor(Color.BLACK);
    canvas.drawArc (rectF, 90, 45, true, p);
}

答案 2 :(得分:4)

我试图做一些与众不同的事情,而且都是关于计算扫描和开始角度的。

我希望显示一个圆弧,表示从上到下的圆圈上的进度。

所以我从0到100有进度值,我希望显示一个从上到下开始的弧,以便在进度为100时填充圆圈。

要计算我使用的sweepAngle:

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

接下来是计算startAngle

    int startAngle = 270 - sweepAngle / 2;

以这种方式计算起始角度,因为:

  1. 它始终从左侧开始,从上到下。所以顶部的起始角度等于270(注意它顺时针方向,0 = 3 o'时钟,所以12 o'时钟等于270度)
  2. 接下来我想计算我离开起点(270)的距离,并且我只计算扫描角度的一半,因为只有一半的弧线在左侧另一半在右边。
  3. 所以考虑到我有25%的进步

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

    如果您希望从其他方面(从左到右,从右到左等)进度,您只需要在开始角度时替换270.

答案 3 :(得分:0)

绘制弧的样本。

from jsonpath_ng.ext import parse

abilityname = "device_info"
propertyname = "manufacturer"
result = parse('$[?(@.name=="' + abilityname + '")].properties[?(@.name=="' + propertyname + '")]').find(myJson)
if len(result) == 1:
    return str(result[0].value['value'])
else:
    return ""

答案 4 :(得分:0)

Langkiller提出了here一个简单的解决方案。从起点到控制点到终点画一条三次线。

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)

答案 5 :(得分:0)

我可能来晚了,但我得到了更多信息。

Android Lollipop 之后,有两种方法可以解决此问题

  

public void drawArc(RectF椭圆形,float startAngle,float sweepAngle,   布尔useCenter,油漆)

     

public void drawArc(向左浮动,向顶部浮动,向右浮动,向下方浮动,   float startAngle,float sweepAngle,boolean useCenter,Paint paint)

用法:

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

后掠角仅是顺时针绘制的扇形角。对于以下代码

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

结果将如下所示

enter image description here

可以通过定义路径,然后在onDraw方法中对其进行迭代来实现相同功能,如以下代码段所示:

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


}

完整的源代码:

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

答案 6 :(得分:0)

enter image description here首先,我们需要从起始角​​度和后掠角度视觉化坐标,然后它将变得更加清晰。

因此,如果您只想要圆的右上角,我们可以做这样的事情:

2N*2N

..

从270度开始(按照上图,向前“倾斜” 90度。您将得到以下形状:

enter image description here

再创建一个,这样您就可以掌握它了。这次让我们使用负值:我们要从右侧开始创建半月形(弧):

 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)

在这里,我们从0开始并“扫过” -180度。 结果是:

enter image description here