Android - 计算弧角

Android - calculate arc angle

我有一个圆弧,我想在 0、45、90、135、180 度处绘制刻度线,任何人都可以帮助我完成此草图上点 5 和点 30 的 x、y 所需的数学运算?:

这是我绘制 1 刻度标记的代码。

   private void drawScale(Canvas canvas) {
        //canvas.drawOval(scaleRect, scalePaint);

        canvas.save();

        Paint p = new Paint();
        p.setColor(Color.WHITE);
        p.setStrokeWidth(10f);
        canvas.drawLine(rectF.left-getWidth()/20, rectF.height()/2, rectF.left, rectF.height()/2, p);


    canvas.restore();
}

如果你知道圆心的点和圆的半径,那么如果你使用矢量对你有利就变得很容易了。

首先你需要每个角度的单位向量

  • 0 度 -> (-1,0)
  • 45 度 -> (-1/sqrt(2), (1/sqrt(2))
  • 90 度 -> (0,1)
  • 135 度 -> (1/sqrt(2), (1/sqrt(2))
  • 180 度 -> (1,0)

然后您可以使用下面的公式计算必要的点数

point = center + (unit vector * distance from center)

这是一个更具体的例子,因为安德鲁添加了一个。

private static final float RADIUS = 400.0f;
private static final float MARK_LENGTH = 30.0f;
private static final UnitVector[] UNIT_VECTORS = new UnitVector[] {
        new UnitVector(-1,0), // 0 deg
        new UnitVector((float) (-1/Math.sqrt(2)), (float) (1/Math.sqrt(2))), // 45 deg
        new UnitVector(0, 1), // 90 deg
        new UnitVector((float) (1/Math.sqrt(2)), (float) (1/Math.sqrt(2))), // 135 deg
        new UnitVector(1, 0), // 180 deg
        new UnitVector((float) (1/Math.sqrt(2)), (float) (-1/Math.sqrt(2))), // 225 deg
        new UnitVector(0, -1), // 270 deg
        new UnitVector((float) (-1/Math.sqrt(2)), (float) (-1/Math.sqrt(2))), // 315 deg
};

static class UnitVector {
    final float x;
    final float y;

    UnitVector(final float x, final float y) {
        this.x = x;
        this.y = y;
    }
}

// Call this from onDraw
public void drawMarks(final Canvas canvas) {
    for (final UnitVector unitVector : UNIT_VECTORS) {
        this.drawMarkWithVector(unitVector, canvas);
    }
}

private void drawMarkWithVector(final UnitVector unitVector, final Canvas canvas) {
    final float centerPointX = this.getWidth() / 2;
    final float centerPointY = this.getHeight() / 2;
    final float startX = centerPointX + (unitVector.x * RADIUS);
    final float startY = centerPointY + (unitVector.y * RADIUS);
    final float endX = centerPointX + (unitVector.x * (RADIUS + MARK_LENGTH));
    final float endY = centerPointY + (unitVector.y * (RADIUS + MARK_LENGTH));
    canvas.drawLine(startX, startY, endX, endY, this.paint);
}

这是上面代码的结果

您可以使用 sincos 计算其旋转。假设您有零点 A 并希望将其旋转到旋转 30° 的 B 点。 像这样:

基本上新点在(cx+x,cy+y)。在这种特殊情况下,sincos 的定义如下:

sin = x/R
cos = y/R

不难得到准确的xy。因此,要在已知半径的圆中以特定角度旋转点,我们需要用下一种方式计算坐标:

x = cx + sin(angle) * R; 
y = cy + cos(angle) * R;

现在让我们回到 Android 和 Canvas!

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.save();
    float cx = getWidth() / 2f;
    float cy = getHeight() / 2f;

    float scaleMarkSize = getResources().getDisplayMetrics().density * 16; // 16dp
    float radius = Math.min(getWidth(), getHeight()) / 2;

    for (int i = 0; i < 360; i += 45) {
        float angle = (float) Math.toRadians(i); // Need to convert to radians first

        float startX = (float) (cx + radius * Math.sin(angle));
        float startY = (float) (cy - radius * Math.cos(angle));

        float stopX = (float) (cx + (radius - scaleMarkSize) * Math.sin(angle));
        float stopY = (float) (cy - (radius - scaleMarkSize) * Math.cos(angle));

        canvas.drawLine(startX, startY, stopX, stopY, scalePaint);
    }

    canvas.restore();
}

代码将以 45° 的步长绘制标记。请注意,您需要将角度转换为弧度,对于 Y 轴,我在 canvas 上使用减号,因为它被翻转了。这是我得到的: