// Java 3D Test Applet // TCBSplinePathTest.java // Copyright (c) 1999 ENDO Yasuyuki // mailto:yasuyuki@javaopen.org // http://www.javaopen.org/j3dbook/index.html import java.applet.*; import java.awt.*; import java.awt.event.*; import javax.media.j3d.*; import javax.vecmath.*; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.universe.SimpleUniverse; import com.sun.j3d.utils.behaviors.picking.PickRotateBehavior; import com.sun.j3d.utils.behaviors.picking.PickTranslateBehavior; import com.sun.j3d.utils.behaviors.picking.PickZoomBehavior; import com.sun.j3d.utils.behaviors.picking.PickObject; import com.sun.j3d.utils.behaviors.picking.PickingCallback; import com.sun.j3d.utils.geometry.ColorCube; import com.sun.j3d.utils.geometry.Primitive; import com.sun.j3d.utils.geometry.Box; import com.sun.j3d.utils.behaviors.interpolators.RotPosScaleTCBSplinePathInterpolator; import com.sun.j3d.utils.behaviors.interpolators.TCBKeyFrame; public class TCBSplinePathTest extends Applet { private Canvas3D canvas = null; private SimpleUniverse universe = null; private BranchGroup scene = null; private Point3f[] points = null; private TCBKeyFrame[] keys = null; private TransformGroup[] strans = null; private AlphaPanel apanel = null; private TransformGroup ctrans = null; private BoundingSphere bounds = null; private RotPosScaleTCBSplinePathInterpolator rinterp = null; public TCBSplinePathTest() { this.setLayout(new BorderLayout()); apanel = new AlphaPanel(); this.add(apanel, BorderLayout.NORTH); Panel ppanel = new Panel(); ppanel.setLayout( new GridLayout(4, 0) ); this.add(ppanel, BorderLayout.SOUTH); Panel[] ppanels = new Panel[4]; for (int i=0; i<4; i++) { ppanels[i] = new Panel(); ppanel.add(ppanels[i]); } final Button sbutton = new Button("Gen"); sbutton.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { String blabel = sbutton.getLabel(); if (blabel.equals("Gen")) { universe.getLocale().removeBranchGraph(scene); removeChild(scene, rinterp); rinterp = createInterpolator(apanel.getAlpha(), ctrans, keys, bounds); addChild(scene, rinterp); apanel.reset(); universe.addBranchGraph(scene); sbutton.setLabel("Stop"); } else if (blabel.equals("Stop")) { rinterp.setEnable(false); sbutton.setLabel("Gen"); } } }); ppanels[0].add(sbutton); ppanels[0].add( new Label("k0") ); TextField k0field = new TextField("0.0"); k0field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float k = 0.0f; try { k = Float.parseFloat(e.getActionCommand()); if (k < 0.0f) k = 0.0f; if (k > 1.0f) k = 1.0f; keys[0].knot = k; } catch (NumberFormatException ex) {} } }); ppanels[0].add(k0field); Checkbox l0check = new Checkbox("L", false); l0check.addItemListener( new ItemListener() { public void itemStateChanged(ItemEvent e) { int state = e.getStateChange(); if (state == ItemEvent.SELECTED) { keys[0].linear = 1; } else if (state == ItemEvent.DESELECTED) { keys[0].linear = 0; } } }); ppanels[0].add(l0check); ppanels[0].add( new Label("t0") ); TextField t0field = new TextField("0.0"); t0field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float t = 0.0f; try { t = Float.parseFloat(e.getActionCommand()); if (t < -1.0f) t = -1.0f; if (t > 1.0f) t = 1.0f; keys[0].tension = t; } catch (NumberFormatException ex) {} } }); ppanels[0].add(t0field); ppanels[0].add( new Label("c0") ); TextField c0field = new TextField("0.0"); c0field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float c = 0.0f; try { c = Float.parseFloat(e.getActionCommand()); if (c < -1.0f) c = -1.0f; if (c > 1.0f) c = 1.0f; keys[0].continuity = c; } catch (NumberFormatException ex) {} } }); ppanels[0].add(c0field); ppanels[0].add( new Label("b0") ); TextField b0field = new TextField("0.0"); b0field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float b = 0.0f; try { b = Float.parseFloat(e.getActionCommand()); keys[0].bias = b; } catch (NumberFormatException ex) {} } }); ppanels[0].add(b0field); ppanels[0].add( new Label("s0") ); TextField s0field = new TextField("1.0"); s0field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float s = 0.0f; try { s = Float.parseFloat(e.getActionCommand()); keys[0].scale = new Point3f(s, s, s); Transform3D t3d = new Transform3D(); strans[0].getTransform(t3d); t3d.setScale(s); strans[0].setTransform(t3d); } catch (NumberFormatException ex) {} } }); ppanels[0].add(s0field); ppanels[1].add( new Label("k1") ); TextField k1field = new TextField("0.4"); k1field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float k = 0.0f; try { k = Float.parseFloat(e.getActionCommand()); if (k < 0.0f) k = 0.0f; if (k > 1.0f) k = 1.0f; keys[1].knot = k; } catch (NumberFormatException ex) {} } }); ppanels[1].add(k1field); Checkbox l1check = new Checkbox("L", false); l1check.addItemListener( new ItemListener() { public void itemStateChanged(ItemEvent e) { int state = e.getStateChange(); if (state == ItemEvent.SELECTED) { keys[1].linear = 1; } else if (state == ItemEvent.DESELECTED) { keys[1].linear = 0; } } }); ppanels[1].add(l1check); ppanels[1].add( new Label("t1") ); TextField t1field = new TextField("0.0"); t1field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float t = 0.0f; try { t = Float.parseFloat(e.getActionCommand()); if (t < -1.0f) t = -1.0f; if (t > 1.0f) t = 1.0f; keys[1].tension = t; } catch (NumberFormatException ex) {} } }); ppanels[1].add(t1field); ppanels[1].add( new Label("c1") ); TextField c1field = new TextField("0.0"); c1field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float c = 0.0f; try { c = Float.parseFloat(e.getActionCommand()); if (c < -1.0f) c = -1.0f; if (c > 1.0f) c = 1.0f; keys[1].continuity = c; } catch (NumberFormatException ex) {} } }); ppanels[1].add(c1field); ppanels[1].add( new Label("b1") ); TextField b1field = new TextField("0.0"); b1field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float b = 0.0f; try { b = Float.parseFloat(e.getActionCommand()); keys[1].bias = b; } catch (NumberFormatException ex) {} } }); ppanels[1].add(b1field); ppanels[1].add( new Label("s1") ); TextField s1field = new TextField("1.0"); s1field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float s = 0.0f; try { s = Float.parseFloat(e.getActionCommand()); keys[1].scale = new Point3f(s, s, s); Transform3D t3d = new Transform3D(); strans[1].getTransform(t3d); t3d.setScale(s); strans[1].setTransform(t3d); } catch (NumberFormatException ex) {} } }); ppanels[1].add(s1field); ppanels[2].add( new Label("k2") ); TextField k2field = new TextField("0.6"); k2field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float k = 0.0f; try { k = Float.parseFloat(e.getActionCommand()); if (k < 0.0f) k = 0.0f; if (k > 1.0f) k = 1.0f; keys[2].knot = k; } catch (NumberFormatException ex) {} } }); ppanels[2].add(k2field); Checkbox l2check = new Checkbox("L", false); l2check.addItemListener( new ItemListener() { public void itemStateChanged(ItemEvent e) { int state = e.getStateChange(); if (state == ItemEvent.SELECTED) { keys[2].linear = 1; } else if (state == ItemEvent.DESELECTED) { keys[2].linear = 0; } } }); ppanels[2].add(l2check); ppanels[2].add( new Label("t2") ); TextField t2field = new TextField("0.0"); t2field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float t = 0.0f; try { t = Float.parseFloat(e.getActionCommand()); if (t < -1.0f) t = -1.0f; if (t > 1.0f) t = 1.0f; keys[2].tension = t; } catch (NumberFormatException ex) {} } }); ppanels[2].add(t2field); ppanels[2].add( new Label("c2") ); TextField c2field = new TextField("0.0"); c2field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float c = 0.0f; try { c = Float.parseFloat(e.getActionCommand()); if (c < -1.0f) c = -1.0f; if (c > 1.0f) c = 1.0f; keys[2].continuity = c; } catch (NumberFormatException ex) {} } }); ppanels[2].add(c2field); ppanels[2].add( new Label("b2") ); TextField b2field = new TextField("0.0"); b2field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float b = 0.0f; try { b = Float.parseFloat(e.getActionCommand()); keys[2].bias = b; } catch (NumberFormatException ex) {} } }); ppanels[2].add(b2field); ppanels[2].add( new Label("s2") ); TextField s2field = new TextField("1.0"); s2field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float s = 0.0f; try { s = Float.parseFloat(e.getActionCommand()); keys[2].scale = new Point3f(s, s, s); Transform3D t3d = new Transform3D(); strans[2].getTransform(t3d); t3d.setScale(s); strans[2].setTransform(t3d); } catch (NumberFormatException ex) {} } }); ppanels[2].add(s2field); ppanels[3].add( new Label("k3") ); TextField k3field = new TextField("1.0"); k3field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float k = 0.0f; try { k = Float.parseFloat(e.getActionCommand()); if (k < 0.0f) k = 0.0f; if (k > 1.0f) k = 1.0f; keys[3].knot = k; } catch (NumberFormatException ex) {} } }); ppanels[3].add(k3field); Checkbox l3check = new Checkbox("L", false); l3check.addItemListener( new ItemListener() { public void itemStateChanged(ItemEvent e) { int state = e.getStateChange(); if (state == ItemEvent.SELECTED) { keys[3].linear = 1; } else if (state == ItemEvent.DESELECTED) { keys[3].linear = 0; } } }); ppanels[3].add(l3check); ppanels[3].add( new Label("t3") ); TextField t3field = new TextField("0.0"); t3field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float t = 0.0f; try { t = Float.parseFloat(e.getActionCommand()); if (t < -1.0f) t = -1.0f; if (t > 1.0f) t = 1.0f; keys[3].tension = t; } catch (NumberFormatException ex) {} } }); ppanels[3].add(t3field); ppanels[3].add( new Label("c3") ); TextField c3field = new TextField("0.0"); c3field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float c = 0.0f; try { c = Float.parseFloat(e.getActionCommand()); if (c < -1.0f) c = -1.0f; if (c > 1.0f) c = 1.0f; keys[3].continuity = c; } catch (NumberFormatException ex) {} } }); ppanels[3].add(c3field); ppanels[3].add( new Label("b3") ); TextField b3field = new TextField("0.0"); b3field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float b = 0.0f; try { b = Float.parseFloat(e.getActionCommand()); keys[3].bias = b; } catch (NumberFormatException ex) {} } }); ppanels[3].add(b3field); ppanels[3].add( new Label("s3") ); TextField s3field = new TextField("1.0"); s3field.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { float s = 0.0f; try { s = Float.parseFloat(e.getActionCommand()); keys[3].scale = new Point3f(s, s, s); Transform3D t3d = new Transform3D(); strans[3].getTransform(t3d); t3d.setScale(s); strans[3].setTransform(t3d); } catch (NumberFormatException ex) {} } }); ppanels[3].add(s3field); GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); canvas = new Canvas3D(config); this.add(canvas, BorderLayout.CENTER); universe = new SimpleUniverse(canvas); universe.getViewingPlatform().setNominalViewingTransform(); scene = createSceneGraph(); universe.addBranchGraph(scene); } private BranchGroup createSceneGraph() { BranchGroup root = new BranchGroup(); root.setCapability(BranchGroup.ALLOW_DETACH); bounds = new BoundingSphere(new Point3d(), 100.0); TransformGroup mtrans = new TransformGroup(); mtrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); mtrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); mtrans.setCapability(TransformGroup.ENABLE_PICK_REPORTING); mtrans.setUserData("mtrans"); root.addChild(mtrans); final TransformGroup rtrans = new TransformGroup(); rtrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); rtrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); root.addChild(rtrans); points = new Point3f[4]; points[0] = new Point3f( 0.0f, -0.6f, 0.1f); points[1] = new Point3f(-0.4f, -0.2f, 0.1f); points[2] = new Point3f( 0.4f, 0.2f, 0.1f); points[3] = new Point3f( 0.0f, 0.6f, 0.1f); keys = new TCBKeyFrame[4]; keys[0] = new TCBKeyFrame(0.0f, 0, new Point3f(points[0]), new Quat4f(0.0f, 0.0f, 0.0f, 0.0f), new Point3f(1.0f, 1.0f, 1.0f), 0.0f, 0.0f, 0.0f); keys[1] = new TCBKeyFrame(0.4f, 0, new Point3f(points[1]), new Quat4f(0.0f, 0.0f, 0.0f, 0.0f), new Point3f(1.0f, 1.0f, 1.0f), 0.0f, 0.0f, 0.0f); keys[2] = new TCBKeyFrame(0.6f, 0, new Point3f(points[2]), new Quat4f(0.0f, 0.0f, 0.0f, 0.0f), new Point3f(1.0f, 1.0f, 1.0f), 0.0f, 0.0f, 0.0f); keys[3] = new TCBKeyFrame(1.0f, 0, new Point3f(points[3]), new Quat4f(0.0f, 0.0f, 0.0f, 0.0f), new Point3f(1.0f, 1.0f, 1.0f), 0.0f, 0.0f, 0.0f); TransformGroup[] ptrans = new TransformGroup[4]; for (int i=0; i<4; i++) { Transform3D pt3d = new Transform3D(); pt3d.set( new Vector3f( (Tuple3f)keys[i].position ) ); ptrans[i] = new TransformGroup(pt3d); ptrans[i].setCapability(TransformGroup.ALLOW_TRANSFORM_READ); ptrans[i].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); rtrans.addChild(ptrans[i]); } strans = new TransformGroup[4]; for (int i=0; i<4; i++) { strans[i] = createCube(0.05, new Vector3d(), true); strans[i].setUserData("p" + Integer.toString(i)); ptrans[i].addChild(strans[i]); } PickRotateBehavior mrotator = new PickRotateBehavior(root, canvas, bounds, PickObject.USE_GEOMETRY); mrotator.setupCallback( new PickingCallback() { public void transformChanged(int type, TransformGroup trans) { if (trans != null) { String udata = (String)trans.getUserData(); if (udata != null) { //System.out.println(udata);//DEBUG Transform3D t3d = new Transform3D(); trans.getTransform(t3d); if (udata.equals("mtrans")) { rtrans.setTransform(t3d); } else if (udata.equals("p0")) { Quat4f quat = new Quat4f(); t3d.get(quat); keys[0].quat = quat; // TEST } else if (udata.equals("p1")) { Quat4f quat = new Quat4f(); t3d.get(quat); keys[1].quat = quat; } else if (udata.equals("p2")) { Quat4f quat = new Quat4f(); t3d.get(quat); keys[2].quat = quat; } else if (udata.equals("p3")) { Quat4f quat = new Quat4f(); t3d.get(quat); keys[3].quat = quat; } } } } }); root.addChild(mrotator); PickTranslateBehavior translator = new PickTranslateBehavior(root, canvas, bounds, PickObject.USE_GEOMETRY); translator.setupCallback( new PickingCallback() { public void transformChanged(int type, TransformGroup trans) { if (trans != null) { String udata = (String)trans.getUserData(); if (udata != null) { //System.out.println(udata);//DEBUG Transform3D t3d = new Transform3D(); trans.getTransform(t3d); if (udata.equals("mtrans")) { rtrans.setTransform(t3d); } else if (udata.equals("p0")) { Vector3f pos = new Vector3f(); t3d.get(pos); keys[0].position.x = points[0].x + pos.x; keys[0].position.y = points[0].y + pos.y; } else if (udata.equals("p1")) { Vector3f pos = new Vector3f(); t3d.get(pos); keys[1].position.x = points[1].x + pos.x; keys[1].position.y = points[1].y + pos.y; } else if (udata.equals("p2")) { Vector3f pos = new Vector3f(); t3d.get(pos); keys[2].position.x = points[2].x + pos.x; keys[2].position.y = points[2].y + pos.y; } else if (udata.equals("p3")) { Vector3f pos = new Vector3f(); t3d.get(pos); keys[3].position.x = points[3].x + pos.x; keys[3].position.y = points[3].y + pos.y; } } } } }); root.addChild(translator); PickZoomBehavior zoomer = new PickZoomBehavior(root, canvas, bounds, PickObject.USE_GEOMETRY); zoomer.setupCallback( new PickingCallback() { public void transformChanged(int type, TransformGroup trans) { if (trans != null) { String udata = (String)trans.getUserData(); if (udata != null) { //System.out.println(udata);//DEBUG Transform3D t3d = new Transform3D(); trans.getTransform(t3d); if (udata.equals("mtrans")) { rtrans.setTransform(t3d); } else if (udata.equals("p0")) { Vector3f pos = new Vector3f(); t3d.get(pos); keys[0].position.z = points[0].z + pos.z; } else if (udata.equals("p1")) { Vector3f pos = new Vector3f(); t3d.get(pos); keys[1].position.z = points[1].z + pos.z; } else if (udata.equals("p2")) { Vector3f pos = new Vector3f(); t3d.get(pos); keys[2].position.z = points[2].z + pos.z; } else if (udata.equals("p3")) { Vector3f pos = new Vector3f(); t3d.get(pos); keys[3].position.z = points[3].z + pos.z; } } } } }); root.addChild(zoomer); double[] vertices = { -0.8, -0.8, 0.0, -0.8, 0.8, 0.0, -0.4, -0.8, 0.0, -0.4, 0.8, 0.0, 0.0, -0.8, 0.0, 0.0, 0.8, 0.0, 0.4, -0.8, 0.0, 0.4, 0.8, 0.0, 0.8, -0.8, 0.0, 0.8, 0.8, 0.0, -0.8, -0.8, 0.0, 0.8, -0.8, 0.0, -0.8, -0.4, 0.0, 0.8, -0.4, 0.0, -0.8, 0.0, 0.0, 0.8, 0.0, 0.0, -0.8, 0.4, 0.0, 0.8, 0.4, 0.0, -0.8, 0.8, 0.0, 0.8, 0.8, 0.0 }; LineArray geom = new LineArray( vertices.length / 3, GeometryArray.COORDINATES); geom.setCapability(GeometryArray.ALLOW_INTERSECT); geom.setCoordinates(0, vertices); Shape3D grid = new Shape3D(geom); grid.setCapability(Shape3D.ALLOW_GEOMETRY_READ); mtrans.addChild(grid); mtrans.addChild( createCorner(0.05f, new Vector3d(-0.8, -0.8, 0.0)) ); mtrans.addChild( createCorner(0.05f, new Vector3d( 0.8, -0.8, 0.0)) ); mtrans.addChild( createCorner(0.05f, new Vector3d(-0.8, 0.8, 0.0)) ); mtrans.addChild( createCorner(0.05f, new Vector3d( 0.8, 0.8, 0.0)) ); ctrans = createCube(0.05, new Vector3d(0.0, 0.0, 0.1), false); rtrans.addChild(ctrans); rinterp = createInterpolator(apanel.getAlpha(), ctrans, keys, bounds); rinterp.setEnable(false); root.addChild(rinterp); return root; } private RotPosScaleTCBSplinePathInterpolator createInterpolator( Alpha alpha, TransformGroup trans, TCBKeyFrame[] keys, Bounds bounds ) { Transform3D t3d = new Transform3D(); RotPosScaleTCBSplinePathInterpolator rinterp = new RotPosScaleTCBSplinePathInterpolator(alpha, trans, t3d, keys); rinterp.setSchedulingBounds(bounds); return rinterp; } private TransformGroup createCorner(float size, Vector3d position) { Transform3D t3d = new Transform3D(); t3d.set(position); TransformGroup trans = new TransformGroup(t3d); Appearance app = new Appearance(); Box box = new Box(size, size, size, Primitive.ENABLE_GEOMETRY_PICKING, app); trans.addChild(box); return trans; } private TransformGroup createCube(double size, Vector3d pos, boolean pick) { Transform3D t3d = new Transform3D(); t3d.set(pos); TransformGroup ctrans = new TransformGroup(t3d); ctrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); ctrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); if (pick) ctrans.setCapability(TransformGroup.ENABLE_PICK_REPORTING); ColorCube cube = new ColorCube(size); cube.setCapability(Shape3D.ALLOW_GEOMETRY_READ); cube.getGeometry().setCapability(GeometryArray.ALLOW_INTERSECT); ctrans.addChild(cube); return ctrans; } private void addChild(Group group, Node node) { for (int i=0; i