如何在方形手表上绘制表盘的“刻度”?

4
我目前有这段代码来生成安卓手表表盘周围的刻度。
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);
            }

在圆形表盘上生成刻度很好,但在方形表盘上的效果如下所示:Round ticks on Square, 我希望它们不是圆形的,而是更适合形状的,例如:Square watchface。是否有标准的方法来做这个?我猜我不能再次使用三角函数...
2个回答

3
当然,你需要使用几何和三角函数。例如,在时钟表盘上放置任何一条线,你需要指向中心,因此一部分将是给定的(x,y),另一部分将是arctan2(cy-y,cx-x),它给出了从你所在点朝向中心(cx,cy)的角度,然后只需沿着给定长度r的方向绘制线条,通过从x,y到cos(angle)*r,sin(angle)*r绘制线条。
但是,根据您的示例图像,您可能希望从x,y到x+r,y绘制线条,然后旋转画布以便可以调整这些数字的位置。确保在调整画布矩阵之前进行canvas.save(),并在调整后进行canvas.restore()。
这留下了你想要从哪个形状绘制刻度线及其位置的数学问题。你可以在Path内完成这个过程。因此,定义一个圆角矩形的路径,然后使用PathMeasure类来获取getPosTan(),然后忽略切线,只使用它给出的位置来找到你在圆角矩形周围的位置。或者,根据决定的形状,简单地计算这些位置作为线段或bezier段通过的位置。
例如:
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);
    }

承认它看起来像:

时钟图片

因此,需要更多的工作才能使其看起来像您的图片。但是,这完全可行。路径测量技巧可以适用于任何形状。我避免使用path.addRoundRect,因为该函数受限于Lollipop+版本。您可以查看我对该问题的回答here。其他答案也非常好,可以用来绘制类似圆角矩形的形状。如果您想编写一个信封函数,只需按比例将当前图片缩放到矩形的包络线上,根据t因子绕着时钟走。


如果你有矢量图的模型,你可以直接使用矢量图形并在绘制过程中将该图标放大。在SVG中绘制所需内容,将其转换为Android矢量图形,然后只需将可绘制对象绘制到画布上即可,它会非常小且不含歧义。 - Tatarize
这其实不是一个坏主意。我使用了你的第一个答案,在稍微调整一下后,最终效果还不错。 - nuggetbram

1
角度是现在位置的函数。我暂时没有看到在这种情况下得到闭合形式的技巧。但在最一般的情况下,你可能只需要存储每个刻度线的位置,然后画出通过该点和中心的直线。因此第 i 秒的角度就是
theta(i)=arctan(y_pos(i) / x_pos(i))

假设中心坐标为 (0,0)。在这种情况下,您只需要存储 8 个连续刻度的位置,因为表盘每 90 度周期性,并且关于对角线也对称。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接