Appendix G Appendix G Navigation and Collision Detection for Web-Based 3D Experiment G.1 ImportInG libraries import javax.media.j3d.*; import javax.vecmath.*; import java.awt.event.*; import java.awt.awtevent; import java.util.enumeration; import javax.swing.event.*; import javax.swing.*; G.2 defining class for navigation and collision detection public class NavigatorBehavior extends Behavior implements MouseListener, MouseMotionListener, ActionListener, ItemListener, ChangeListener private TransformGroup viewtrans; private TransformGroup bodytrans; private TransformGroup outsidetrans; private Matrix3f commat = new Matrix3f(); private Shape3D bodyshape; private int direction; private WakeupCriterion eventscondition[] = new WakeupCriterion[3];
Ko & Cheng private WakeupOr allevents; private String buttonvalue = new String(); private boolean poststop = false; private float turningangle = 0.0f; private float pitchangle = 0.0f; private Point3f viewposi = new Point3f(); private Point3f firstviewposi = new Point3f(); private Point3f outsideposi = new Point3f(); private boolean ticked = false; private int delay = 20; private JSlider FrameDelay; private Animation animator; //for animating thread; private boolean animating = false; private BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 0.1); private static final float PAI = 3.14159f; private static final float ANGLEPAI = 2.0f*PAI/360.0f; private static final float SPAN = 0.02f; private static final float ANGLESTEP = 0.01f; private static final float Outsidescale = 0.4f; private static final int VIEWMOTION = 5001; private static final int DOOROPEN = 401; private static final int DOORCLOSE = 402; private static final int ANIMATION = 501; private static final int INTERACTION = 502; private static final int Forward = KeyEvent.VK_UP; private static final int Backward = KeyEvent.VK_DOWN; private static final int LEFT = KeyEvent.VK_LEFT; private static final int RIGHT = KeyEvent.VK_RIGHT; private static final int SHIFTRIGHT = KeyEvent.VK_R; private static final int SHIFTLEFT = KeyEvent.VK_L; private static final int Up = KeyEvent.VK_U; private static final int Down = KeyEvent.VK_D; G.3 constructor of navigation and collision detection function NavigatorBehavior(TransformGroup viewtrans, TransformGroup bodytrans, Shape3D bodyshape) this.bodyshape = bodyshape; this.viewtrans = viewtrans; this.bodytrans = bodytrans;
Appendix G G.4 view platform position InItIalIZatIon public void initposition(point3f initposi) this.viewposi = new Point3f(initposi); firstviewposi = new Point3f(initposi); init(); G.5 setting reference for outside scene public void setoutside(transformgroup outsidetrans, Point3f outsideposi) this.outsidetrans = outsidetrans; this.outsideposi = new Point3f(outsideposi); G.6 setting reference for speed control slider for navigation public void setobject(jslider FrameDelay) this.framedelay = FrameDelay; G.7 parameter InItIalIZatIon private void init() commat.m00 = 1.0f; commat.m01 = 0.0f; commat.m02 = 0.0f; commat.m10 = 0.0f; commat.m11 = 1.0f; commat.m12 = 0.0f; commat.m20 = 0.0f; commat.m21 = 0.0f; commat.m22 = 1.0f;
Ko & Cheng G.8 function for calculation of rotation matrix from rotation angle private Matrix3f comatrix(int mode, float angle) Matrix3f tempmat = new Matrix3f(); switch (mode) case 1: tempmat.m00 = (float)(math.cos(angle)); tempmat.m01 = 0.0f; tempmat.m02 = (float)(math.sin(angle)); tempmat.m10 = 0.0f; tempmat.m11 = 1.0f; tempmat.m12 = 0.0f; tempmat.m20 = (float)(-math.sin(angle)); tempmat.m21 = 0.0f; tempmat.m22 = (float)(math.cos(angle)); case 2: tempmat.m00 = 1.0f; tempmat.m01 = 0.0f; tempmat.m02 = 0.0f; tempmat.m10 = 0.0f; tempmat.m11 = (float)(math.cos(angle)); tempmat.m12 = (float)(math.sin(angle)); tempmat.m20 = 0.0f; tempmat.m21 = (float)(-math.sin(angle)); tempmat.m22 = (float)(math.cos(angle)); case 3: tempmat.m00 = (float)(math.cos(angle)); tempmat.m01 = (float)(-math.sin(angle)); tempmat.m02 = 0.0f; tempmat.m10 = (float)(math.sin(angle)); tempmat.m11 = (float)(math.cos(angle)); tempmat.m12 = 0.0f; tempmat.m20 = 0.0f; tempmat.m21 = 0.0f; tempmat.m22 = 1.0f; default: return tempmat; G.9 function for ImplementatIon of rotation for view platform
Appendix G private void setrotation(transformgroup Trans, float angle, Matrix3f rotmat, int mode) Transform3D rt3d = new Transform3D(); Trans.getTransform(rt3d); rotmat.transpose(); rotmat.invert(); rotmat.mul(rotmat, comatrix(mode, angle)); rt3d.setrotation(rotmat); Trans.setTransform(rt3d); G.10 function for ImplementatIon of translation for view platform private Point3f settranslation(matrix3f rotmat, Point3f posi) Point3f tempposi = new Point3f(); tempposi.x = rotmat.m00*posi.x + rotmat.m01*posi.y + rotmat.m02*(posi.z+0.01f); tempposi.y = rotmat.m10*posi.x + rotmat.m11*posi.y + rotmat.m12*(posi.z+0.01f); tempposi.z = rotmat.m20*posi.x + rotmat.m21*posi.y + rotmat.m22*(posi.z+0.01f); return tempposi; G.11 function for ImplementatIon of translation and rotation for transform Group private void setposition(transformgroup Trans, Point3f point) Transform3D t3d = new Transform3D(); Trans.getTransform(t3d); t3d.settranslation(new Vector3d(point)); Trans.setTransform(t3d); G.12 event InItIalIZatIon function public void initialize() eventscondition[0] = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED); eventscondition[1] = new WakeupOnCollisionEntry(bodyshape); eventscondition[2] = new WakeupOnBehaviorPost(null, VIEWMOTION); allevents = new WakeupOr(eventsCondition); wakeupon(allevents);
0 Ko & Cheng G.13 key events response function for keyboard navigation private void processkeyevent(keyevent e) int key = e.getkeycode(); direction = key; switch(key) case Forward: direction = Forward; viewposi.x = viewposi.x-2.0f*span*(float)math.sin(turningangle); viewposi.z = viewposi.z-2.0f*span*(float)math.cos(turningangle); case Backward: direction = Backward; viewposi.x = viewposi.x+2.0f*span*(float)math.sin(turningangle); viewposi.z = viewposi.z+2.0f*span*(float)math.cos(turningangle); case LEFT: if (pitchangle!=0) setrotation(viewtrans, -pitchangle, commat, 2); pitchangle = 0.0f; setrotation(viewtrans, ANGLESTEP, commat, 1); turningangle += ANGLESTEP; case RIGHT: if (pitchangle!=0) setrotation(viewtrans, -pitchangle, commat, 2); pitchangle = 0.0f; setrotation(viewtrans, -ANGLESTEP, commat, 1); turningangle -= ANGLESTEP; case Up: if (viewposi.y<1.7f)
Appendix G viewposi.y = viewposi.y+span/2.0f; case Down: if (viewposi.y>1.0f) viewposi.y = viewposi.y-span/2.0f; case SHIFTLEFT: direction = SHIFTLEFT; viewposi.x = viewposi.x-span*(float)math.sin(turningangle+math.pi/2.0); viewposi.z = viewposi.z-span*(float)math.cos(turningangle+math.pi/2.0); case SHIFTRIGHT: direction = SHIFTRIGHT; viewposi.x = viewposi.x+span*(float)math.sin(turningangle+math.pi/2.0); viewposi.z = viewposi.z+span*(float)math.cos(turningangle+math.pi/2.0); default: G.14 main events response function for navigating and collision detection public void processstimulus(enumeration criteria) WakeupCriterion wakeup; AWTEvent[] event; int eventid; if (!animating) while (criteria.hasmoreelements())
Ko & Cheng wakeup = (WakeupCriterion) criteria.nextelement(); if (wakeup instanceof WakeupOnAWTEvent) event = ((WakeupOnAWTEvent)wakeup).getAWTEvent(); for (int i=0; i<event.length; i++) processkeyevent((keyevent) event[i]); if (wakeup instanceof WakeupOnBehaviorPost) try Thread.sleep(delay); catch (Exception ie) System.out.println( Interrupted Exception! ); if (buttonvalue.indexof( Forward )!= -1) direction = Forward; viewposi.x = viewposi.x-2.0f*span*(float)math.sin(turningangle); viewposi.z = viewposi.z-2.0f*span*(float)math.cos(turningangle); else if (buttonvalue.indexof( Backward )!= -1) direction = Backward; viewposi.x = viewposi.x+2.0f*span*(float)math.sin(turningangle); viewposi.z = viewposi.z+2.0f*span*(float)math.cos(turningangle); else if (buttonvalue.indexof( Turnleft )!= -1) if (pitchangle!=0) setrotation(viewtrans, -pitchangle, commat, 2); pitchangle = 0.0f; setrotation(viewtrans, ANGLESTEP, commat, 1); turningangle += ANGLESTEP; else if (buttonvalue.indexof( Turnright )!= -1) if (pitchangle!=0) setrotation(viewtrans, -pitchangle, commat, 2); pitchangle = 0.0f;
Appendix G setrotation(viewtrans, -ANGLESTEP, commat, 1); turningangle -= ANGLESTEP; else if (buttonvalue.indexof( Pitchup )!= -1) if (pitchangle>-10.0f*anglepai) setrotation(viewtrans, -ANGLESTEP, commat, 2); pitchangle -= ANGLESTEP; else if (buttonvalue.indexof( Pitchdown )!= -1) if (pitchangle<10.0f*anglepai) setrotation(viewtrans, ANGLESTEP, commat, 2); pitchangle += ANGLESTEP; else if (buttonvalue.indexof( Yawleft )!= -1) else if (buttonvalue.indexof( Yawright )!= -1) else if (buttonvalue.indexof( Horizontal )!= -1) if (pitchangle!=0) setrotation(viewtrans, -pitchangle, commat, 2); pitchangle = 0.0f; else if (buttonvalue.indexof( Original )!= -1) viewposi = new Point3f(firstviewposi); if (pitchangle!=0) setrotation(viewtrans, -pitchangle, commat, 2); pitchangle = 0.0f; if (turningangle!=0) setrotation(viewtrans, -turningangle, commat, 1); turningangle = 0.0f;
Ko & Cheng else if (buttonvalue.indexof( Up )!= -1) if (viewposi.y<1.7f) viewposi.y = viewposi.y+span/2.0f; else if (buttonvalue.indexof( Down )!= -1) if (viewposi.y>1.0f) viewposi.y = viewposi.y-span/2.0f; else if (buttonvalue.indexof( Shiftleft )!= -1) direction = SHIFTLEFT; viewposi.x = viewposi.x-span*(float)math.sin(turningangle+math.pi/2.0); viewposi.z = viewposi.z-span*(float)math.cos(turningangle+math.pi/2.0); else if (buttonvalue.indexof( Shiftright )!= -1) direction = SHIFTRIGHT; viewposi.x = viewposi.x+span*(float)math.sin(turningangle+math.pi/2.0); viewposi.z = viewposi.z+span*(float)math.cos(turningangle+math.pi/2.0); if (poststop) postid(viewmotion); if (wakeup instanceof WakeupOnCollisionEntry) // The implememtation of the collision function, go back two step when // the collision occurs in order to obtain the next collision ability switch (direction) case Forward: viewposi.x = viewposi.x+4.0f*span*(float)math.sin(turningangle); viewposi.z = viewposi.z+4.0f*span*(float)math.cos(turningangle);
Appendix G case Backward: viewposi.x = viewposi.x-4.0f*span*(float)math.sin(turningangle); viewposi.z = viewposi.z-4.0f*span*(float)math.cos(turningangle); case SHIFTLEFT: viewposi.x = viewposi.x+2.0f*span*(float)math.sin(turningangle+math.pi/2.0); viewposi.z = viewposi.z+2.0f*span*(float)math.cos(turningangle+math.pi/2.0); case SHIFTRIGHT: viewposi.x = viewposi.x-2.0f*span*(float)math.sin(turningangle+math.pi/2.0); viewposi.z = viewposi.z-2.0f*span*(float)math.cos(turningangle+math.pi/2.0); default: this.wakeupon(allevents); G.15 events function for navigation control panel public void actionperformed(actionevent e) String radiobutton = e.getactioncommand(); if (radiobutton.indexof( Animation )!=-1) animating = true; viewposi = new Point3f(firstviewposi); if (pitchangle!=0) setrotation(viewtrans, -pitchangle, commat, 2); pitchangle = 0.0f;
Ko & Cheng if (turningangle!=0) setrotation(viewtrans, -turningangle, commat, 1); turningangle = 0.0f; setposition(outsidetrans, new Point3f(Outsidescale*viewposi.x, outsideposi.y, outsideposi.z)); postid(dooropen); if (animator == null) animator = new Animation(); animator.running = true; else if (!animator.running) animator.running = true; else if (radiobutton.indexof( Interaction )!=-1) animating = false; viewposi = new Point3f(firstviewposi); if (pitchangle!=0) setrotation(viewtrans, -pitchangle, commat, 2); pitchangle = 0.0f; if (turningangle!=0) setrotation(viewtrans, -turningangle, commat, 1); turningangle = 0.0f; postid(doorclose); if (animator!= null) if (animator.animationthread.isalive()) animator.running = false; //quit the measuring loop animator = null;
Appendix G G.16 mouse release events function public void mousereleased(mouseevent e) poststop = false; G.17 function for mouse pressed events for IdentIfyInG Icons on navigating panel public void mousepressed(mouseevent e) buttonvalue = null; int positionx = e.getx(); int positiony = e.gety(); if(positionx>722 && positionx<734 && positiony>58 && positiony<71) buttonvalue = Shiftleft ; else if(positionx>826 && positionx<839 && positiony>55 && positiony<69) buttonvalue = Shiftright ; else if(positionx>772 && positionx<788 && positiony>7 && positiony<21) buttonvalue = Up ; else if(positionx>772 && positionx<788 && positiony>102 && positiony<114) buttonvalue = Down ; else if(positionx>785 && positionx<798 && positiony>40 && positiony<52) buttonvalue = Forward ; else if(positionx>758 && positionx<771 && positiony>74 && positiony<86) buttonvalue = Backward ; else if(positionx>767 && positionx<791 && positiony>52 && positiony<64) buttonvalue = Original ; else if(positionx>883 && positionx<896 && positiony>53 && positiony<73) buttonvalue = Turnleft ; else if(positionx>974 && positionx<985 && positiony>52 && positiony<75)
Ko & Cheng buttonvalue = Turnright ; else if(positionx>922 && positionx<944 && positiony>14 && positiony<22) buttonvalue = Pitchup ; else if(positionx>922 && positionx<942 && positiony>100 && positiony<113) buttonvalue = Pitchdown ; else if(positionx>925 && positionx<942 && positiony>57 && positiony<77) buttonvalue = Horizontal ; if (buttonvalue!= null) poststop = true; postid(viewmotion); G.18 function for mouse exit event public void mouseexited(mouseevent e) G.19 function for mouse entry event public void mouseentered(mouseevent e) G.20 function for mouse click event public void mouseclicked(mouseevent e)
Appendix G G.21 function for mouse move event public void mousemoved(mouseevent e) G.22 function for mouse drag event public void mousedragged(mouseevent e) G.23 function for dragging of speed control slider panel public void statechanged(changeevent e) if (e.getsource().tostring().indexof( majortickspacing=2 )!=-1) delay = (10-FrameDelay.getValue())*15; G.24 function for clicking mode buttons on navigation panel public void itemstatechanged(itemevent e) if (e.getsource().tostring().indexof( Keyboard )!=-1) if (e.getstatechange() == ItemEvent.DESELECTED) ticked = false; else ticked = true;
0 Ko & Cheng G.25 animation thread class for continuous movement WhIle navigating Icons Is held or animation mode button Is clicked class Animation implements Runnable boolean running = false; Thread AnimationThread; public Animation() AnimationThread = new Thread(this); AnimationThread.start(); //call function run() to begin to measure public void run() try AnimationThread.sleep(1000); catch (Exception ie) System.out.println( Interrupted Exception! ); while (running) if (viewposi.z>-2.0f) viewposi.z = viewposi.z - 2.0f*SPAN; setposition(outsidetrans, new Point3f(Outsidescale*viewposi.x, outsideposi.y, outsideposi.z)); else viewposi.z=-2.0f; setrotation(viewtrans, ANGLESTEP, commat, 1); turningangle += ANGLESTEP; try AnimationThread.sleep(80); catch (Exception ie) System.out.println( Interrupted Exception! ); AnimationThread.interrupt(); //stop measuring // end of class NavigatorBehavior