问题描述
这是我所提到的书中作为解决方案给出的表达,但似乎超出了我的理解。请任何人帮助理解我们如何准确地写出这个角度?为什么要减去 pi / 2 ?我真的不知道
xs=(int)(Math.cos(s*3.14f/30-3.14f/2)*45+xcentre);
ys=(int)(Math.sin(s*3.14f/30-3.14f/2)*45+ycentre);
xm=(int)(Math.cos(m*3.14f/30-3.14f/2)*40+xcentre);
ym=(int)(Math.sin(m*3.14f/30-3.14f/2)*40+ycentre);
xh=(int)(Math.cos((h*30+m/2)*3.14f/180-3.14f/2)*30+xcentre);
yh=(int)(Math.sin((h*30+m/2)*3.14f/180-3.14f/2)*30+ycentre);
解决方法
似乎是在给定以原点为中心的三个时钟指针两端的直角坐标,向上为负y,向右为正x。我可以通过尝试一些值来说明这一点。
我将您的基本代码包装如下:
static class ClockCoords {
int xs,ys;
int xm,ym;
int xh,yh;
public String toString() {
return String.format("h: %3d,%3d m: %3d,%3d s: %3d,%3d",xh,yh,xm,ym,xs,ys);
}
}
public static ClockCoords coords(int h,int m,int s) {
ClockCoords r = new ClockCoords();
int xcentre = 0;
int ycentre = 0;
r.xs = (int) (Math.cos(s * 3.14f / 30 - 3.14f / 2) * 45 + xcentre);
r.ys = (int) (Math.sin(s * 3.14f / 30 - 3.14f / 2) * 45 + ycentre);
r.xm = (int) (Math.cos(m * 3.14f / 30 - 3.14f / 2) * 40 + xcentre);
r.ym = (int) (Math.sin(m * 3.14f / 30 - 3.14f / 2) * 40 + ycentre);
r.xh = (int) (Math.cos((h * 30 + m / 2) * 3.14f / 180 - 3.14f / 2) * 30 + xcentre);
r.yh = (int) (Math.sin((h * 30 + m / 2) * 3.14f / 180 - 3.14f / 2) * 30 + ycentre);
return r;
}
public static void main(String[] args) throws IOException {
System.out.println(coords(0,0));
System.out.println(coords(0,45));
System.out.println(coords(6,0));
System.out.println(coords(6,30,0));
}
这给了我这个
h: 0,-29 m: 0,-39 s: 0,-44
h: 0,-39 s: -44,0
h: 0,29 m: 0,-44
h: -7,28 m: 0,39 s: 0,-44
因此,如果我还没弄错的话,时针长29单位,分针长39单位,秒针长44单位。在一天的开始,第一个条目,他们都直指上。在第二天进入日期45秒后,秒针指向左侧,但在给定整数粒度和不太长的手的情况下,其他两只手仍指向上。第三个条目6:00只是将时针翻转指向下方。第四项很有趣,即6:30,它使分针指向下方,但时针也向左和向上移动了一点……我们的第一只手不在与中心成90度角的位置。有趣的东西。至于所有这些的原因...我认为这都是基本的三角学和笛卡尔数学。
等等,有一件事我不明白...我在公式中看到每只手的长度不同。为什么我从公式中看到的手长只有1?我的猜测是,它与所使用的PI非常近似。我认为这些手并没有指向正上方。这就是我能想到的。也许明天我会尝试为PI插入更高的价值。
,让我也为您提供一些背景信息。
三角学
都是围绕一个圆,半径为1个单位,以Origo为中心,即点(0,0)。圆上一点的坐标可以计算为x =cosα,y =sinα,其中α是角度。由于圆的所有点到中心的距离相等,因此您只需要知道角度即可计算坐标,即(cos(alpha),sin(alpha))。
原因:看一下Pythagoras's theorem,这是law of cosines的结果,其中三角形的最大角度为90度。
毕达哥拉斯定理指出
其中a,b和c是三角形的边长,三角形是垂直的,并且 a
弧度,PI / 2
角度单位可以度(360度为整圆)或弧度(2 PI为整圆)进行测量。让我们谈谈弧度。在数学上,0弧度是圆的最高点的角度。 pi / 2是最左侧的。 pi是最低的。 3pi / 2是最右边的。请注意,随着角度的增加,您的点将逆时针移动。
由于这是周期性的,所以确实如此
2 * k * pi + alpha = alpha
在屏幕上,y指向下方,而数学标准中y顶点指向上方。因此,如果您从0弧度开始,那将是在屏幕上显示时的最低点,并且由于倒数y,随着角度的增加,您将朝顺时针方向移动。从0删除pi / 2会将您指向最右边。
变量
- (xh,yh)是小时坐标
- (xm,ym)是分钟坐标
- (xs,ys)是第二个坐标
它们是传统时钟的指针。
- h是小时角
- m是分钟角度
- s是第二个角度
(xcentre,ycentre)是中心的坐标。它们可能不同于(0,0),因此坐标移动,支持所谓的平移。
步长
一分钟有60秒,一小时有60分钟,所以角度步长必须相同,即使一天中有24小时,步长的频率也不同,因此,小时的角度步长既不应该频繁出现,又要更大(传统时钟上为12个位置)。
手长
时针,分针和秒针(无双关)的长度不同,这就是为什么将三角圆的单位分别乘以45、40和30的原因。
随着时间的流逝,大概角度会发生变化,随后其坐标也会发生变化。
,一个不那么详尽的解释,只看几秒钟:
xs = (int)(Math.cos(s*3.14f/30-3.14f/2)*45+xcentre);
ys = (int)(Math.sin(s*3.14f/30-3.14f/2)*45+ycentre);
正如Steve's answer所指出的那样,从(xcentre,ycentre)
到(xs,ys)
画一条线将显示秒针,“ up”为“ y = 0”-从而使轴反转比较传统地块。这实际上对我们有利:在正常情况下,随着角度的增加,它们将显示为逆时针方向。由于y
轴的屏幕坐标是反向的,因此这对我们来说很好:我们的手将按预期的顺时针方向前进。
让我们使用xs
看一下数学:
xs = Math.cos(s*3.14f/30-3.14f/2)*45; // removed rounding & using xcentre=0
xs = Math.cos((s/30)*PI - PI/2) * sHandLength; // use PI=3.14...,sHandLength=45
现在,在时间0,我们希望秒针朝上看。但通常是cos(0) = 1
。如果我们减去90º(PI/2
),它会一直向上看:
xs = Math.cos((s/30)*PI - zeroIsUp) * sHandLength;
我们可以撤消此操作以继续推理其余表达式:
xs = Math.cos((s/30)*PI); // sHandlength of 1,time 0 is left
所缺少的只是那个神秘的s/30*PI
。我们来做一张小桌子:
seconds(s) radians(argument to Math.cos())
0 0
15 PI/2 -- a quarter-turn of the hand
30 PI -- a half-turn
45 3*PI/2 -- a three-quarters turn
60 2*PI,or 0 -- a full turn
因此,看来(s/30) * PI
简直是(s/60) * (2*PI)
的缩写。
对于一本有关Java的书,我期望有一种更清晰的书写方式。我个人的偏好是:
xs = (int)(Math.cos(base60toRadians(s) - zeroIsUp) * secondHandLength + xCentre);
ys = (int)(Math.sin(base60toRadians(s) - zeroIsUp) * secondHandLength + yCentre);
// ... somewhere else
private float base60toRadians(int b60) { return (b60 / 60) * (2 * Math.PI); }
,
时钟中心的坐标为(xcentre,ycentre)。 通过将几何仿射平移到中心,您可以像从(0,0)进行计算。
指针沿负方向顺时针旋转。
现在,钟针的顶部为(0,1),角度为π/ 2(90°)。 (1,0)是角度开始的地方,(-1,0)的中途是角度π(180°)。 360°的完整角度为2π,其1/60 变为:
秒:60秒=2π;角2π/ 60 =π/ 30
double startAngle = Math.PI / 2; // Value 0 has angle π/2
double rs = 45;
xs = (int)(Math.cos(-s * Math.PI / 30 - startAngle) * rs + xcentre);
ys = ... sin ...
小时:24小时=2π;角2π/ 24 =π/ 12