2015-05-03 70 views
4

我有一个弧,我希望在0,45,90,135,180度绘制比例标记,任何人都可以帮助我实现点5和30的x,y所需的数学在这个小品?:Android - 计算弧角

enter image description here

这里是我绘制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(); 
} 

回答

11

可以使用sincos计算其旋转的结果。让我们假设你有零点A并且想把它旋转到旋转30°的点B。 事情是这样的:

enter image description here

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

sin = x/R 
cos = y/R 

不难得到确切xy。因此,要在特定的角度圆圈,我们需要在接下来的方式来计算坐标知道半径旋转点:

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

现在,让我们回到Android和帆布!

@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轴,我在画布上使用减号原因将其翻转。以下是我有:

enter image description here

+1

不错,你可以使用['Canvas.translate '](http://developer.android.com/reference/android/graphics/Canvas.html#translate(float,%20float))来设置中心,那么你可以忘掉它。它看起来像你想过的,因为你保存和恢复画布矩阵。 – weston

+0

'canvas.translate(-cx,-cy)';然后删除所有其他对'cx','cy'的引用 – weston

4

如果你知道圆的中心点和圆的半径,如果你使用向量来获得优势,它变得非常容易。

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

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

下面是代码的上述 Result of the code

+0

首先,感谢你的帮助,第二,我不是所有的伟大在这种数学的,所以如果你能请澄清对我来说: 1.什么是单位矢量? 2。有什么意义? 3.标记长度是多少? 再次感谢您的帮助 –

+0

认为单位矢量的简化方法是将其视为指向特定方向的长度线。这意味着如果你想在单位矢量的方向上移动一个特定长度的点,只需将单位矢量乘以所需的长度并将其添加到原始点。得出的结论是我在等式中提到的一点。一些更多信息在这里https://www.mathsisfun.com/algebra/vector-unit.html 标记长度是你画的线条的长度。 –

+0

添加了一个更具体的例子,因为安德鲁增加了一个。这两种方法都很好,并且有上升趋势。安德鲁斯解决方案更通用,并允许您更改标记绘制的角度。我的解决方案在计算上花费较少,因为它可以避免执行trig数学运算。 –