package nl.tudelft.simulation.dsol.animation.D3; import java.awt.geom.Point2D; import java.rmi.RemoteException; import java.util.Enumeration; import javax.media.j3d.BranchGroup; import javax.media.j3d.Group; import javax.media.j3d.Node; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.naming.Context; import javax.naming.NamingException; import javax.vecmath.AxisAngle4d; import javax.vecmath.Vector3d; import nl.tudelft.simulation.dsol.animation.LocatableInterface; import nl.tudelft.simulation.dsol.animation.StaticLocation; import nl.tudelft.simulation.dsol.simulators.SimulatorInterface; import nl.tudelft.simulation.language.d3.DirectedPoint; import nl.tudelft.simulation.logger.Logger; import nl.tudelft.simulation.naming.context.ContextUtil; /** * Renderable3D, a 3d renderable
* (c) copyright 2002-2005 Delft University of Technology , the * Netherlands.
* See for project information www.simulation.tudelft.nl
* License of use: Lesser General Public License (LGPL) , no * warranty. * @version $Revision: 1.1 $ $Date: 2010/08/10 11:37:27 $ * @author Roy Chin */ public abstract class Renderable3D extends BranchGroup implements Renderable3DInterface { /** * the source of this animatableObject */ protected LocatableInterface source = null; /** * the simulator */ protected SimulatorInterface simulator = null; /** * Rotation group */ protected TransformGroup locationGroup = null; /** * Type of renderable (world, static or simulated */ protected int type = Renderable3DInterface.DYNAMIC_OBJECT; /** * Scale: temporary solution This scale is used to scale translations and can also be used to scale the model * (shape). This is a temporary solution as we would actually like to scale the entire content branch, but this is * not possible yet */ protected double scale = 1.0d; /** * translation Used in update; put here to prevent garbage */ private Transform3D translate = new Transform3D(); /** * combined rotation angle Used in update; put here to prevent garbage */ private Transform3D rotate = new Transform3D(); /** * yaw angle Used in update; put here to prevent garbage */ private Transform3D yaw = new Transform3D(); /** * pitch angle Used in update; put here to prevent garbage */ private Transform3D pitch = new Transform3D(); /** * roll angle Used in update; put here to prevent garbage */ private Transform3D roll = new Transform3D(); /** * @param simulator SimulatorInterface */ public Renderable3D(final SimulatorInterface simulator) { if (!LocatableInterface.class.isAssignableFrom(this.getClass())) { throw new IllegalArgumentException("this class should implement Locatable interface"); } this.source = (LocatableInterface) this; this.simulator = simulator; this.initialize(); } /** * @param staticLocation Point3d * @param simulator SimulatorInterface */ public Renderable3D(final DirectedPoint staticLocation, final SimulatorInterface simulator) { super(); this.source = new StaticLocation(staticLocation, null); this.simulator = simulator; this.type = Renderable3DInterface.STATIC_OBJECT; this.initialize(); } /** * @param staticLocation Point3d * @param branchGroup A branchGroup containing (a part of) the model * @param simulator SimulatorInterface */ public Renderable3D(final DirectedPoint staticLocation, final BranchGroup branchGroup, final SimulatorInterface simulator) { super(); this.source = new StaticLocation(staticLocation, null); this.simulator = simulator; this.type = Renderable3DInterface.STATIC_OBJECT; this.initializeTransformGroups(); this.provideModel(this.locationGroup); this.addChild(this.locationGroup); this.addChild(branchGroup); this.update(); try { Context context = ContextUtil.lookup(this.simulator.getReplication().getContext(), "/animation/3D"); ContextUtil.bind(context, this); } catch (RemoteException | NamingException exception) { Logger.warning(this, "", exception); } } /** * @param staticLocation Point2D * @param simulator SimulatorInterface */ public Renderable3D(final Point2D staticLocation, final SimulatorInterface simulator) { this(new DirectedPoint(staticLocation), simulator); } /** * @param source LocatableInterface * @param simulator SimulatorInterface */ public Renderable3D(final LocatableInterface source, final SimulatorInterface simulator) { super(); this.source = source; this.simulator = simulator; this.initialize(); } /** * Initialize. */ private void initialize() { // Note: the order of the lines below does matter! // AnimationFrame3D wants to draw as soon as it has // got the object from the context, so transforms // better be initialized. // // Note2: RunControl.notify() must create the subcontext: // "/animation3d" this.initializeTransformGroups(); this.provideModel(this.locationGroup); this.addChild(this.locationGroup); this.update(); try { Context context = ContextUtil.lookup(this.simulator.getReplication().getContext(), "/animation/3D"); ContextUtil.bind(context, this); } catch (RemoteException | NamingException exception) { Logger.warning(this, "", exception); } } /** * Initialize TransformGroups. */ private void initializeTransformGroups() { this.setCapability(Group.ALLOW_CHILDREN_READ); this.setCapability(Group.ALLOW_CHILDREN_WRITE); this.setCapability(Group.ALLOW_CHILDREN_EXTEND); this.setCapability(BranchGroup.ALLOW_DETACH); this.setCapability(Node.ENABLE_PICK_REPORTING); // Determine if this branch group is pickable if (this.type == Renderable3DInterface.DYNAMIC_OBJECT) { this.setPickable(true); } else { this.setPickable(false); } this.locationGroup = new TransformGroup(); this.locationGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); this.locationGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); this.locationGroup.setCapability(Group.ALLOW_CHILDREN_READ); this.locationGroup.setCapability(Group.ALLOW_CHILDREN_WRITE); this.locationGroup.setCapability(Group.ALLOW_CHILDREN_EXTEND); if (this.type == Renderable3DInterface.DYNAMIC_OBJECT) { this.locationGroup.setCapabilityIsFrequent(TransformGroup.ALLOW_TRANSFORM_READ); this.locationGroup.setCapabilityIsFrequent(TransformGroup.ALLOW_TRANSFORM_READ); } } /** * Provide the 3D model and add it to the locationGroup * @param locationGroup The location of the object */ protected abstract void provideModel(final TransformGroup locationGroup); /** * updates the renderable */ public void update() { try { this.update(this.getAllChildren()); DirectedPoint location = this.getSource().getLocation(); this.translate.set(new Vector3d(location.x * this.scale, location.y * this.scale, location.z * this.scale)); // Hope the order of the rotations is correct .. this.yaw.setRotation(new AxisAngle4d(0, 0, 1, location.getRotX())); this.pitch.setRotation(new AxisAngle4d(0, 1, 0, location.getRotZ())); this.roll.setRotation(new AxisAngle4d(1, 0, 0, location.getRotY())); // first translate then rotate this.rotate.set(this.translate); this.rotate.mul(this.yaw); this.rotate.mul(this.pitch); this.rotate.mul(this.roll); this.locationGroup.setTransform(this.rotate); } catch (RemoteException exception) { this.rotate.set(new Vector3d(0, 0, 0)); Logger.warning(this, "update", exception); } } /** * Method update. * @param children the children to update. */ protected abstract void update(final Enumeration children); /** * @return LocatableInterface */ public LocatableInterface getSource() { return this.source; } /** * returns the type * @return the returned type. */ public int getType() { return this.type; } /** * @return scale */ public double getScale() { return this.scale; } /** * @param scale Set the scale of the coordinates */ public void setScale(final double scale) { this.scale = scale; } }