上一篇文章介绍了实时跟踪程序中画点的操作,在这里介绍如果实现程序跟踪的动画回放。实现动画回放的基本原理是不停的刷新
JPanel
,在每次刷新的过程中,把图片画在相邻的位置便可以实现动画的效果。
为了实现动画的回放,需要使用
Thread
进行不停的刷新。回顾一下线路数据结构:线路的
ID
,线路的名称,线路的所有点的集合,线路的图片名称,线路的交通工具,为了实现动画,还需要为线路添加一个记录动画位置的类,命名为
Cartoon,Cartoon
类包含了当前动画位置的
curX,curY
坐标,当前倾斜的角度
angle,
在画
JPanel
的
painComponent
方法中调用路线的画图方法,便可以画出线路,
Route
类需要遍历每个
Stone
点,对于每个点调用点的画图方法,之后再根据点的先后画出两个点之间的连线,在连线也画好的情况下再根据
Cartoon
的坐标和旋转角度画出相应的交通工具,这就是线路画图的所有步骤。另外在必要的情况下开启一个线程,线程拥有指向
JPanel
的句柄,从
JPanel
中获取线路的句柄,再从线路的句柄中获取
Cartoon
的句柄,线程便可以根据线路中的两个点计算刷新时图片的位置,线程休眠一段时间,再次计算图片的位置,调用
JPanel
进行刷新,反复执行,便可以得到动画。在这个过程中,线程的开始可以由事件触发,线程的结束可以根据当前线路是否已经到达最后来作为退出条件,或者被中断。
假设目前动画需要走的线段由两个点决定,比如
preStone,
前一个点,
curStone
当前点。图标需要从
preStone
走到
curStone,
首先需要计算出目前行进的角度,确定角度的目的是使得图标做出相应的旋转,更逼真的演示现实的状况。计算角度需要知道坐标的具体值,命名变量
x1,y1
为
preStone
的坐标,
x2,y2
为
curStone
的坐标,
dx
,
dy
分别为
x2-x1,y2-y1
,则
dy/dx
即为当前角度的
tan(angle)
的值,使用反正且函数便可以得出当前的角度,
dx
需要分为三种情况讨论,
1
,
dx>0
,则其角度应该在第一和第四象限,象限的概念是初中的知识,如果不明白的请再温习一下初中的教科书,反正切的值在
-PI/2
到
PI/2
之间,直接旋转既为正确答案,
2.dx<0
则其角度在第二和第三象限,需要在得到反正切之后再旋转
180
度得到,因此其值为
atan(dy/dx)+PI,
这样经过旋转之后便为正确答案,
3
,如果
dx
为零,则需要判断
dy
与零的关系,如果
dy
大于
0
,则需要旋转
PI/2,
如果
dy
小于零,则需要旋转
-PI/2,
如果为
0
,则旋转角度可以为
0
;以上的分析逻辑可以得到如下的程序:
int x1, y1, x2, y2, dx, dy, steps;
x1 = preStone.getX();
y1 = preStone.getY();
x2 = curStone.getX();
y2 = curStone.getY();
dx = x2 - x1;
dy = y2 - y1;
double angle = 0;
if (dx > 0) {
angle = Math.atan(dy * 1.0 / dx * 1.0);
} else if (dx < 0) {
angle = Math.PI + Math.atan(dy * 1.0 / dx);
} else if (dx == 0) {
if (dy >= 0) {
angle = Math.PI / 2;
} else {
angle = Math.PI * 3 / 2;
}
}
cartoon.setAngle(angle);
注意:在进行反正切的过程中整数相除必须转换为双精度相除,否则类似于
30/33
其结果为
0
,这就会使得精度大打折扣。
得到了旋转的角度后,便需要在两点之间找出每次画图标所处的坐标。作者的思想是首先算出当前两点之间的距离
L
,循环由
0
到
L
根据步长遍历,利用相似三角形的原理和坐标平移的原理得到目前遍历的点的坐标,程序如下
:
steps = (int) Math.round(Math.sqrt(dx * dx + dy * dy));
得到两点之间的总长度,即步长,
for (int i = 0; i <= steps; i += 3) {
//
循环从
0
到总步长,每次增加三个步长。
curX = (int) Math.round(x1 + 1.0 * dx * i / steps);
根据相似三角形的原理得到当前的
x
轴坐标
curY = (int) Math.round(y1 + 1.0 * dy * i / steps);
根据相似三角形的原理得到当前的
Y
轴坐标
当所有的点已经准备好了,便可以刷新
Jpanel
了,
JPanel
的刷新会调用调用
PaintComponent
方法,
paintComponent
又会调用
Route
的画图方法,在
route
的画图方法中使用当前的设置画出图标,画图标的过程如下:得到图标的
URL
,根据
URL
得到
ImageICon
的图标,取出图标的高和宽度,克隆一个坐标系,对坐标系进行旋转,并把坐标系设置到
Graphic
,在相应位置的画出图标,使得图标的中心点在给定的
x,y
上,还原原来的
graphic
的坐标系。这样整个图标便画完了。实现代码如下:
URL url = getClass().getResource("/icon/" + getVehicle() + ".gif");
ImageIcon vIcon = new ImageIcon(url);
int height = vIcon.getIconHeight();
int width = vIcon.getIconWidth();
AffineTransform origXform = g.getTransform();
AffineTransform newXform = (AffineTransform) (origXform.clone());
int xRot = cartoon.getCurX();
int yRot = cartoon.getCurY();
newXform.rotate(cartoon.getAngle(), xRot, yRot);
g.setTransform(newXform);
g.drawImage(vIcon.getImage(), xRot - width / 2, yRot - height / 2,
null);
g.setTransform(origXform);
作者简介:凌辉
北京*******科技发展有限公司
软件开发部
项目经理,数据库方向研究生学历,设计开发过多个
J2EE
应用程序,有丰富的软件开发、管理、测试经验,擅长网站应用程序开发,在设计模式,软件重构,版本控制,软件保护,数据库设计与管理等方面都有独特的见解。