org.scijava.java3d.utils.universe.ViewingPlatform Maven / Gradle / Ivy
Show all versions of j3dutils Show documentation
/*
* Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any
* kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
* EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
* NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
* USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
* ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
* INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or
* maintenance of any nuclear facility.
*
*/
package org.scijava.java3d.utils.universe;
import java.util.Enumeration;
import java.util.Hashtable;
import org.scijava.java3d.BranchGroup;
import org.scijava.java3d.Group;
import org.scijava.java3d.Transform3D;
import org.scijava.java3d.TransformGroup;
import org.scijava.java3d.View;
import org.scijava.java3d.ViewPlatform;
import org.scijava.vecmath.Vector3d;
import org.scijava.java3d.internal.J3dUtilsI18N;
import org.scijava.java3d.utils.behaviors.vp.ViewPlatformBehavior;
/**
* This class is used to set up the "view" side of a Java 3D scene graph.
* The ViewingPlatform object contains a MultiTransformGroup node to allow
* for a series of transforms to be linked together. To this structure
* the ViewPlatform is added as well as any geometry to associate with this
* view platform.
*
* @see ViewPlatform
*/
public class ViewingPlatform extends BranchGroup {
/**
* Cached ViewPlatform associated with this ViewingPlatform object.
*/
protected ViewPlatform viewPlatform;
/**
* MultiTransformGroup that holds all TransformGroups between
* the BranchGroup and the View object.
*/
protected MultiTransformGroup mtg;
/**
* Used to keep track of added geometry. When geometry
* is added to the view platform, an addChild to this BranchGroup
* is performed.
*/
protected BranchGroup platformGeometryRoot;
/**
* Used to keep track of added geometry. When geometry
* is added for an avatar, an addChild to this BranchGroup
* is performed.
*/
protected BranchGroup avatarRoot;
/**
* Cached PlatformGeometry object.
*/
protected PlatformGeometry platformGeometry = null;
/**
* Table of the Viewer objects.
*/
protected Hashtable viewerList;
/**
* Used to keep track of behaviors.
*
* @since Java 3D 1.2.1
*/
protected BranchGroup behaviors;
/**
* The universe to which this viewing platform is attached
*
* @since Java 3D 1.3
*/
protected SimpleUniverse universe;
/**
* Creates a default ViewingPlatform object. This consists of a
* MultiTransfromGroup node with one transform and a ViewPlatform
* object. The ViewPlatform is positioned at (0.0, 0.0, 0.0).
*/
public ViewingPlatform() {
// Call main constructor with default values.
this(1);
}
/**
* Creates the ViewingPlatform object. This consists of a
* MultiTransfromGroup node with the specified number of transforms
* (all initialized to the identity transform).
* and a ViewPlatform object.
*
* @param numTransforms The number of transforms the MultiTransformGroup
* node should contain. If this number is less than 1, 1 is assumed.
*/
public ViewingPlatform(int numTransforms) {
viewerList = new Hashtable();
// Set default capabilities for this node.
setCapability(Group.ALLOW_CHILDREN_WRITE);
setCapability(Group.ALLOW_CHILDREN_EXTEND);
setCapability(BranchGroup.ALLOW_DETACH);
// Create MultiTransformGroup node.
if (numTransforms < 1)
numTransforms = 1;
mtg = new MultiTransformGroup(numTransforms);
// Get first transform and add it to the scene graph.
TransformGroup tg = mtg.getTransformGroup(0);
addChild(tg);
// Create ViewPlatform and add it to the last transform in the
// MultiTransformGroup node.
tg = mtg.getTransformGroup(numTransforms - 1);
viewPlatform = new ViewPlatform();
viewPlatform.setCapability(ViewPlatform.ALLOW_POLICY_READ);
viewPlatform.setCapability(ViewPlatform.ALLOW_POLICY_WRITE);
tg.addChild(viewPlatform);
// Set capabilities to allow for changes when live.
tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
// Initialize the avatarRoot BranchGroup node and add it to the
// last transform in the MultiTransformGroup node.
avatarRoot = new BranchGroup();
avatarRoot.setCapability(Group.ALLOW_CHILDREN_READ);
avatarRoot.setCapability(Group.ALLOW_CHILDREN_WRITE);
avatarRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND);
tg.addChild(avatarRoot);
// Initialize the platformGeometry BranchGroup node and add it to the
// last transform in the MultiTransformGroup node.
platformGeometryRoot = new BranchGroup();
platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_READ);
platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_WRITE);
platformGeometryRoot.setCapability(Group.ALLOW_CHILDREN_EXTEND);
tg.addChild(platformGeometryRoot);
}
/**
* Sets the ViewPlatform node for this ViewingPlatform object.
*
* @param vp The ViewPlatform node to associate with this ViewingPlatform
* object.
*/
public void setViewPlatform(ViewPlatform vp) {
TransformGroup tg = getViewPlatformTransform();
tg.removeChild(viewPlatform);
tg.addChild(vp);
viewPlatform = vp;
// Assign this to all Viewers.
Enumeration e = viewerList.keys();
while (e.hasMoreElements())
((Viewer)e.nextElement()).setViewingPlatform(this);
}
/**
* Returns the ViewPlatform node for this ViewingPlatform object.
*
* @return The ViewPlatform node associated with this ViewingPlatform
* object.
*/
public ViewPlatform getViewPlatform() {
return viewPlatform;
}
/**
* Assigns the geometry to associate with the ViewingPlatform.
* PlatformGeometry is used to hold any geometry to be associated
* with the ViewingPlatform. If the ViewingPlatform is to be the
* inside of a car, for instance, than the PlatformGeometry could be
* the dashboard of the car.
*
* @param pg The geometry to be associated with this ViewingPlatform.
* Passing in null has the effect of deleting any geometry associated
* with this ViewingPlatform.
*/
public void setPlatformGeometry(PlatformGeometry pg) {
// Just return if trying to set the same PlatformGeometry object.
if (platformGeometry == pg)
return;
// If the PlatformGeometry is null, will be removing any geometry
// already present.
if (pg == null) {
if (platformGeometryRoot.numChildren() != 0)
platformGeometryRoot.removeChild(0);
}
else {
// See if there is an old PlatformGeometry to replace.
if (platformGeometryRoot.numChildren() != 0)
platformGeometryRoot.setChild(pg, 0);
else {
platformGeometryRoot.addChild(pg);
}
}
platformGeometry = pg;
}
/**
* Returns the PlatformGeometry associated with this ViewingPlatform
*
* @return The PlatformGeometry associated with this ViewingPlatform
*/
public PlatformGeometry getPlatformGeometry() {
return platformGeometry;
}
/**
* Returns the MultitransformGroup object for this
* ViewingPlatform object.
*
* @return The MultitransformGroup object.
*/
public MultiTransformGroup getMultiTransformGroup() {
return mtg;
}
/**
* Returns a reference to the "bottom most" transform in the
* MultiTransformGroup that is above the ViewPlatform node.
*
* @return The TransformGroup that is immediately above the
* ViewPlatform object.
*/
public TransformGroup getViewPlatformTransform() {
return mtg.getTransformGroup(mtg.getNumTransforms() - 1);
}
/**
* Sets the nominal viewing distance in the ViewPlatform transform based
* on the current field of view. If the ViewAttachPolicy is not the
* default of View.NOMINAL_HEAD, then this method has no effect.
*
* The ViewPlatform is moved back along Z so that objects at the origin
* spanning the normalized X range of -1.0 to +1.0 can be fully viewed
* across the width of the window. This is done by setting a translation
* of 1/(tan(fieldOfView/2)) in the ViewPlatform transform.
*
* If there is no Viewer object associated with this ViewingPlatform
* object the default field of view of PI/4.0 is used.
*
* NOTE: Support for multiple Viewer objects is not available. If
* multiple viewers are attached to this ViewingPlatform than a
* RuntimeException will be thrown.
*/
public void setNominalViewingTransform() {
if (viewPlatform.getViewAttachPolicy() == View.NOMINAL_HEAD) {
double fieldOfView;
if (viewerList.size() == 0) {
// No Viewer associated with this ViewingPlatform, so use the
// default field of view value to move the ViewingPlatform.
fieldOfView = Math.PI/4.0;
}
else {
if (viewerList.size() > 1) {
throw new RuntimeException
(J3dUtilsI18N.getString("ViewingPlatform0"));
}
Viewer viewer = (Viewer)viewerList.keys().nextElement();
View view = viewer.getView();
fieldOfView = view.getFieldOfView();
}
Transform3D t3d = new Transform3D();
double viewDistance = 1.0/Math.tan(fieldOfView/2.0);
t3d.set(new Vector3d(0.0, 0.0, viewDistance));
getViewPlatformTransform().setTransform(t3d);
}
}
/**
* Returns the avatarRoot child number of the ViewerAvatar object.
* All the children of the avatarRoot are compared with the passed
* in ViewerAvatar. If a match is found, the index is returned.
*
* @param avatar The ViewerAvatar object to look for in the avatarRoot's
* child nodes.
* @return The index of the child that corresponds to the ViewerAvatar.
* If the avatarRoot does not contain the ViewerAvatar -1 is returned.
*/
private int findAvatarChild(ViewerAvatar avatar) {
// Search the avatarRoot for the ViewerAvatar associated with
// with the Viewer object
for (int i = 0; i < avatarRoot.numChildren(); i++) {
if (((ViewerAvatar)avatarRoot.getChild(i)) == avatar)
return i;
}
// Should never get here.
System.err.println("ViewingPlatform.findAvatarChild:Child not found.");
return -1;
}
/**
* Adds the ViewerAvatar to the scene graph. An avatar (geometry)
* can be associated with a Viewer object and displayed by Java 3D.
*
* @param viewer The viewer object to associate with this avatar.
* @param avatar The avatar to add to the scene graph. Passing in
* null removes any currently assigned avatar.
*/
void setAvatar(Viewer viewer, ViewerAvatar avatar) {
Object oldAvatar = viewerList.get(viewer);
// A position of -1 means the avatar is not a child of the avatarRoot.
int avatarPosition = -1;
// Because "null" cannot be used in a put the avatarRoot object
// is used to signify that there is no ViewerAvatar associated
// with this Viewer.
if (oldAvatar != avatarRoot)
avatarPosition = findAvatarChild((ViewerAvatar)oldAvatar);
// If the avatar is null, will be removing any geometry already present.
if (avatar == null) {
if (avatarPosition != -1) {
avatarRoot.removeChild(avatarPosition);
// Reset hashtable entry - avatarRoot == null.
viewerList.put(viewer, avatarRoot);
}
}
else {
// see if there is an old ViewerAvater to replace
if (avatarPosition != -1)
avatarRoot.setChild(avatar, avatarPosition);
else
avatarRoot.addChild(avatar);
// Update hashtable with new avatar.
viewerList.put(viewer, avatar);
}
}
/**
* When a ViewingPlatform is set by a Viewer, the ViewingPlatform
* needs to be informed, via a call to this method. This will add
* the Viewer to the ViewingPlatform's viewerList for use when
* things such as the PlatformGeometry are changed and all Viewer
* scene graphs need to be modified.
*/
void addViewer(Viewer viewer) {
// Because the viewerList is also used to associate ViewerAvatars
// with Viewer objects a hashtable is used. This routine does not
// check for the presence of a ViewerAvatar but the Viewer still
// needs to be added to the hashtable. Because "null" cannot be
// used in a put the avatarRoot object is used to signify that there
// is no ViewerAvatar associated with this Viewer.
viewerList.put(viewer, avatarRoot);
}
/*
* Cleanup when Viewer set another ViewingPlatform
*/
void removeViewer(Viewer viewer) {
viewerList.remove(viewer);
}
/**
* Adds a new ViewPlatformBehavior to the ViewingPlatform
*/
void addViewPlatformBehavior(ViewPlatformBehavior behavior) {
behavior.setViewingPlatform(this);
if (behaviors == null) {
behaviors = new BranchGroup();
behaviors.setCapability(BranchGroup.ALLOW_DETACH);
behaviors.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
}
// otherwise detach the BranchGroup so we can add to it
else {
behaviors.detach();
}
behaviors.addChild(behavior);
this.addChild(behaviors);
}
/**
* Sets the ViewPlatformBehavior which will operate on the ViewPlatform
* transform (the TransformGroup returned by
* ViewingPlatform.getViewPlatformTransform()). The ViewPlatformBehavior
* may be set after the ViewingPlatform is setLive().
* If a behavior is already present, it will be detached and it's
* setViewingPlatform method will be called with a parameter of null.
* @param behavior The ViewPlatformBehavior to add to the ViewingPlatform.
* null will remove the ViewingPlatform behavior.
* @since Java 3D 1.2.1
*/
public void setViewPlatformBehavior(ViewPlatformBehavior behavior) {
if (behaviors != null) {
removeViewPlatformBehavior((ViewPlatformBehavior)behaviors.getChild(0));
}
if (behavior != null) {
addViewPlatformBehavior(behavior);
}
}
/**
* Removes the specified ViewPlatformBehavior
*/
void removeViewPlatformBehavior(ViewPlatformBehavior behavior) {
// remove from the behaviors branch group
if (behaviors != null) {
behaviors.detach();
for (int i = 0; i < behaviors.numChildren(); i++) {
if (behaviors.getChild(i) == behavior) {
behavior.setViewingPlatform( null );
behaviors.removeChild(i);
break;
}
}
if (behaviors.numChildren() == 0) behaviors = null;
else this.addChild(behaviors);
}
}
/**
* Returns the number of ViewPlatformBehaviors on the ViewingPlatform
*/
int getViewPlatformBehaviorCount() {
return behaviors.numChildren();
}
/**
* Returns the ViewPlatformBehavior at the specified index
*/
ViewPlatformBehavior getViewPlatformBehavior(int index) {
return (ViewPlatformBehavior)behaviors.getChild(index);
}
/**
* Returns the ViewPlatformBehavior
* @return the ViewPlatformBehavior for the ViewingPlatform.
* Returns null if there is no ViewPlatformBehavior set.
* @since Java 3D 1.2.1
*/
public ViewPlatformBehavior getViewPlatformBehavior() {
if (behaviors == null) {
return null;
}
return getViewPlatformBehavior(0);
}
/**
* Returns the Viewers attached to this ViewingPlatform
*
* @return the Viewers attached to this viewing platform
* @since Java 3D 1.3
*/
public Viewer[] getViewers() {
if (viewerList.size() == 0) return null;
return (Viewer[])viewerList.keySet().toArray( new Viewer[0] );
}
/**
* Returns the Universe to which this ViewingPlatform is attached
*
* @return the Universe to which this ViewingPlatform is attached
* @since Java 3D 1.3
*/
public SimpleUniverse getUniverse() {
return universe;
}
/**
* Sets the Universe to which this ViewingPlatform is attached
*
* @param universe the Universe to which this ViewingPlatform is attached
* @since Java 3D 1.3
*/
public void setUniverse( SimpleUniverse universe ) {
this.universe = universe;
}
}