上一篇文章介绍了实时跟踪程序中画点的操作,在这里介绍如果实现程序跟踪的动画回放。实现动画回放的基本原理是不停的刷新JPanel,在每次刷新的过程中,把图片画在相邻的位置便可以实现动画的效果。
       为了实现动画的回放,需要使用Thread进行不停的刷新。回顾一下线路数据结构:线路的ID,线路的名称,线路的所有点的集合,线路的图片名称,线路的交通工具,为了实现动画,还需要为线路添加一个记录动画位置的类,命名为Cartoon,Cartoon类包含了当前动画位置的curX,curY 坐标,当前倾斜的角度angle,在画JPanelpainComponent方法中调用路线的画图方法,便可以画出线路,Route类需要遍历每个Stone点,对于每个点调用点的画图方法,之后再根据点的先后画出两个点之间的连线,在连线也画好的情况下再根据Cartoon的坐标和旋转角度画出相应的交通工具,这就是线路画图的所有步骤。另外在必要的情况下开启一个线程,线程拥有指向JPanel的句柄,从JPanel中获取线路的句柄,再从线路的句柄中获取Cartoon的句柄,线程便可以根据线路中的两个点计算刷新时图片的位置,线程休眠一段时间,再次计算图片的位置,调用JPanel进行刷新,反复执行,便可以得到动画。在这个过程中,线程的开始可以由事件触发,线程的结束可以根据当前线路是否已经到达最后来作为退出条件,或者被中断。
       假设目前动画需要走的线段由两个点决定,比如preStone,前一个点,curStone当前点。图标需要从preStone走到curStone,首先需要计算出目前行进的角度,确定角度的目的是使得图标做出相应的旋转,更逼真的演示现实的状况。计算角度需要知道坐标的具体值,命名变量x1,y1preStone的坐标,x2,y2curStone 的坐标,dxdy分别为x2-x1,y2-y1,则dy/dx即为当前角度的tan(angle)的值,使用反正且函数便可以得出当前的角度,dx需要分为三种情况讨论,1dx>0,则其角度应该在第一和第四象限,象限的概念是初中的知识,如果不明白的请再温习一下初中的教科书,反正切的值在-PI/2PI/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;
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

                            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,循环由0L根据步长遍历,利用相似三角形的原理和坐标平移的原理得到目前遍历的点的坐标,程序如下:
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应用程序,有丰富的软件开发、管理、测试经验,擅长网站应用程序开发,在设计模式,软件重构,版本控制,软件保护,数据库设计与管理等方面都有独特的见解。
联系方式:QQ21731278 msn[email]lili00okok123@hotmail.com[/email]