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);
}
这是上面代码的结果
您可以使用 sin
和 cos
计算其旋转。假设您有零点 A
并希望将其旋转到旋转 30° 的 B
点。
像这样:
基本上新点在(cx+x,cy+y)
。在这种特殊情况下,sin
和 cos
的定义如下:
sin = x/R
cos = y/R
不难得到准确的x
和y
。因此,要在已知半径的圆中以特定角度旋转点,我们需要用下一种方式计算坐标:
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 上使用减号,因为它被翻转了。这是我得到的:
我有一个圆弧,我想在 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);
}
这是上面代码的结果
您可以使用 sin
和 cos
计算其旋转。假设您有零点 A
并希望将其旋转到旋转 30° 的 B
点。
像这样:
基本上新点在(cx+x,cy+y)
。在这种特殊情况下,sin
和 cos
的定义如下:
sin = x/R
cos = y/R
不难得到准确的x
和y
。因此,要在已知半径的圆中以特定角度旋转点,我们需要用下一种方式计算坐标:
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 上使用减号,因为它被翻转了。这是我得到的: