如何在方形手表上绘制表盘'ticks'?
How to draw watchface 'ticks' on a square watch?
我目前有这个代码片段在 android wear watchface
的外部生成刻度线
float innerMainTickRadius = mCenterX - 35;
for(int tickIndex = 0; tickIndex < 12; tickIndex++) {
float tickRot = (float) (tickIndex * Math.PI * 2 / 12);
float innerX = (float) Math.sin(tickRot) * innerMainTickRadius;
float innerY = (float) -Math.cos(tickRot) * innerMainTickRadius;
float outerX = (float) Math.sin(tickRot) * mCenterX;
float outerY = (float) -Math.cos(tickRot) * mCenterX;
canvas.drawLine(mCenterX + innerX, mCenterY + innerY, mCenterX + outerX, mCenterY + outerY, mTickPaint);
}
在圆形表盘上可以很好地生成刻度,但在方形表盘上会变成这样:
但我希望它们不是圆形的,而是更适合形状,例如:
有没有标准的方法来做到这一点?我猜我不能再使用三角了...
角度是现在位置的函数。在这种情况下,我没有立即看到获得封闭形式的技巧。但在最一般的情况下,您最终可能只存储每个刻度线的位置,然后您只需绘制穿过该点和中心的线。所以第 i 秒的角度只是
theta(i)=arctan(y_pos(i) / x_pos(i))
假设圆心坐标为(0,0)。在这种情况下,您只需要存储 8 个连续刻度的位置,因为面每 90 度是周期性的并且关于对角线也是对称的。
你当然会用到几何和三角。例如,您在钟面上放置的任何一条线都希望指向中心,因此一部分将是给定的 (x,y),另一部分将是 arctan2(cy-y,cx-x) 给您从指向中心 (cx,cy) 然后简单地在给定长度 r 的中心方向画线,通过从 x,y 到 cos(angle) * r, sin(angle) * r 画线.
但是,根据您的示例图像,您可能想要绘制从 x,y 到 x+r,y 的直线,然后按角度旋转 canvas,这样您就可以绘制像那样调整的数字。确保在调整 canvas' 矩阵之前执行 canvas.save() 并在调整之后执行 canvas.restore()。
这留下了你想要从中绘制刻度的任何形状及其位置的数学。您可以在路径中执行此操作。因此,定义圆角矩形的路径,然后使用 PathMeasure class 获取 getPosTan(),然后忽略切线,仅使用它为您提供的位置来找到圆角矩形周围的位置。那或简单地将这些位置计算为通过线段或贝塞尔曲线的位置,具体取决于决定的形状。
例如:
static final int TICKS = 12;
static final float TICKLENGTH = 20;
在绘制例程中,
float left = cx - 50;
float top = cy - 50;
float right = cx + 50;
float bottom = cy + 50;
float ry = 20;
float rx = 20;
float width = right-left;
float height = bottom-top;
Path path = new Path();
path.moveTo(right, top + ry);
path.rQuadTo(0, -ry, -rx, -ry);
path.rLineTo(-(width - (2 * rx)), 0);
path.rQuadTo(-rx, 0, -rx, ry);
path.rLineTo(0, (height - (2 * ry)));
path.rQuadTo(0, ry, rx, ry);
path.rLineTo((width - (2 * rx)), 0);
path.rQuadTo(rx, 0, rx, -ry);
path.rLineTo(0, -(height - (2 * ry)));
path.close();
PathMeasure pathMeasure = new PathMeasure();
pathMeasure.setPath(path,true);
float length = pathMeasure.getLength();
float[] pos = new float[2];
float r = TICKLENGTH;
for (int i = 0; i < TICKS; i++) {
pathMeasure.getPosTan(i * (length/TICKS),pos,null);
double angle = Math.atan2(cy - pos[1], cx - pos[0]); //yes, y then x.
double cos = Math.cos(angle);
double sin = Math.sin(angle);
canvas.drawLine(pos[0], pos[1], (float)(pos[0] + cos * r), (float)(pos[1] + sin * r), paint);
}
不可否认,它看起来像:
所以要使它看起来像您的图像需要更多的工作。但是,这是完全可行的。路径测量技巧适用于任何形状。由于 Lollipop+ 限制,我避免使用 path.addRoundRect。你可以看到我对那个问题的回答here。其他答案非常适合如何绘制圆角矩形形状。如果您想编写包络函数,只需根据因子 t 将当前图片缩放到矩形的包络,因为它全天候运行。
我目前有这个代码片段在 android wear watchface
的外部生成刻度线float innerMainTickRadius = mCenterX - 35;
for(int tickIndex = 0; tickIndex < 12; tickIndex++) {
float tickRot = (float) (tickIndex * Math.PI * 2 / 12);
float innerX = (float) Math.sin(tickRot) * innerMainTickRadius;
float innerY = (float) -Math.cos(tickRot) * innerMainTickRadius;
float outerX = (float) Math.sin(tickRot) * mCenterX;
float outerY = (float) -Math.cos(tickRot) * mCenterX;
canvas.drawLine(mCenterX + innerX, mCenterY + innerY, mCenterX + outerX, mCenterY + outerY, mTickPaint);
}
在圆形表盘上可以很好地生成刻度,但在方形表盘上会变成这样:
有没有标准的方法来做到这一点?我猜我不能再使用三角了...
角度是现在位置的函数。在这种情况下,我没有立即看到获得封闭形式的技巧。但在最一般的情况下,您最终可能只存储每个刻度线的位置,然后您只需绘制穿过该点和中心的线。所以第 i 秒的角度只是
theta(i)=arctan(y_pos(i) / x_pos(i))
假设圆心坐标为(0,0)。在这种情况下,您只需要存储 8 个连续刻度的位置,因为面每 90 度是周期性的并且关于对角线也是对称的。
你当然会用到几何和三角。例如,您在钟面上放置的任何一条线都希望指向中心,因此一部分将是给定的 (x,y),另一部分将是 arctan2(cy-y,cx-x) 给您从指向中心 (cx,cy) 然后简单地在给定长度 r 的中心方向画线,通过从 x,y 到 cos(angle) * r, sin(angle) * r 画线.
但是,根据您的示例图像,您可能想要绘制从 x,y 到 x+r,y 的直线,然后按角度旋转 canvas,这样您就可以绘制像那样调整的数字。确保在调整 canvas' 矩阵之前执行 canvas.save() 并在调整之后执行 canvas.restore()。
这留下了你想要从中绘制刻度的任何形状及其位置的数学。您可以在路径中执行此操作。因此,定义圆角矩形的路径,然后使用 PathMeasure class 获取 getPosTan(),然后忽略切线,仅使用它为您提供的位置来找到圆角矩形周围的位置。那或简单地将这些位置计算为通过线段或贝塞尔曲线的位置,具体取决于决定的形状。
例如:
static final int TICKS = 12;
static final float TICKLENGTH = 20;
在绘制例程中,
float left = cx - 50;
float top = cy - 50;
float right = cx + 50;
float bottom = cy + 50;
float ry = 20;
float rx = 20;
float width = right-left;
float height = bottom-top;
Path path = new Path();
path.moveTo(right, top + ry);
path.rQuadTo(0, -ry, -rx, -ry);
path.rLineTo(-(width - (2 * rx)), 0);
path.rQuadTo(-rx, 0, -rx, ry);
path.rLineTo(0, (height - (2 * ry)));
path.rQuadTo(0, ry, rx, ry);
path.rLineTo((width - (2 * rx)), 0);
path.rQuadTo(rx, 0, rx, -ry);
path.rLineTo(0, -(height - (2 * ry)));
path.close();
PathMeasure pathMeasure = new PathMeasure();
pathMeasure.setPath(path,true);
float length = pathMeasure.getLength();
float[] pos = new float[2];
float r = TICKLENGTH;
for (int i = 0; i < TICKS; i++) {
pathMeasure.getPosTan(i * (length/TICKS),pos,null);
double angle = Math.atan2(cy - pos[1], cx - pos[0]); //yes, y then x.
double cos = Math.cos(angle);
double sin = Math.sin(angle);
canvas.drawLine(pos[0], pos[1], (float)(pos[0] + cos * r), (float)(pos[1] + sin * r), paint);
}
不可否认,它看起来像:
所以要使它看起来像您的图像需要更多的工作。但是,这是完全可行的。路径测量技巧适用于任何形状。由于 Lollipop+ 限制,我避免使用 path.addRoundRect。你可以看到我对那个问题的回答here。其他答案非常适合如何绘制圆角矩形形状。如果您想编写包络函数,只需根据因子 t 将当前图片缩放到矩形的包络,因为它全天候运行。