//
// DisplayRendererJ3D.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad.java3d;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import java.util.Enumeration;
import java.util.Vector;
import javax.media.j3d.Appearance;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.GeometryArray;
import javax.media.j3d.GraphicsContext3D;
import javax.media.j3d.Group;
import javax.media.j3d.Node;
import javax.media.j3d.OrderedGroup;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.SceneGraphObject;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Switch;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.View;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4d;
import visad.AxisScale;
import visad.ColorAlphaControl;
import visad.ColorControl;
import visad.ContourControl;
import visad.Control;
import visad.ControlEvent;
import visad.DataRenderer;
import visad.Display;
import visad.DisplayException;
import visad.DisplayImpl;
import visad.DisplayRealType;
import visad.DisplayRenderer;
import visad.Flow1Control;
import visad.Flow2Control;
import visad.GraphicsModeControl;
import visad.MouseBehavior;
import visad.KeyboardBehavior;
import visad.PlotText;
import visad.ProjectionControl;
import visad.RangeControl;
import visad.RealType;
import visad.RendererControl;
import visad.RendererSourceListener;
import visad.ScalarMap;
import visad.ShapeControl;
import visad.TextControl;
import visad.VisADException;
import visad.VisADLineArray;
import visad.VisADRay;
import visad.VisADTriangleArray;
import visad.util.Util;
/**
* <CODE>DisplayRendererJ3D</CODE> is the VisAD abstract super-class for
* background and metadata rendering algorithms. These complement
* depictions of <CODE>Data</CODE> objects created by
* <CODE>DataRenderer</CODE> objects.<P>
*
* <CODE>DisplayRendererJ3D</CODE> also manages the overall relation of
* <CODE>DataRenderer</CODE> output to Java3D and manages the scene graph.<P>
*
* It creates the binding between <CODE>Control</CODE> objects and scene
* graph <CODE>Behavior</CODE> objects for direct manipulation of
* <CODE>Control</CODE> objects.<P>
*
* <CODE>DisplayRendererJ3D</CODE> is not <CODE>Serializable</CODE> and
* should not be copied between JVMs.<P>
*/
public abstract class DisplayRendererJ3D
extends DisplayRenderer
implements RendererSourceListener
{
/**
* Set the name of a <code>SceneGraphObject</code>.
* If <code>SceneGraphObject</code> does not have a <code>setName</code>
* (J3D pre v1.4) this is a no-op.
* @param name
*/
public static void setSceneGraphObjectName(SceneGraphObject obj, String name) {
Util.setName(obj, name);
}
private Object not_destroyed = new Object();
// for screen locked
private OrderedGroup screen_locked = null;
private TransformGroup locked_trans = null;
/** View associated with this VirtualUniverse */
private View view;
/** VisADCanvasJ3D associated with this VirtualUniverse */
private VisADCanvasJ3D canvas;
/** root BranchGroup of scene graph under Locale */
private BranchGroup root = null;
/** single TransformGroup between root and BranchGroups for all
* Data depictions */
private TransformGroup trans = null;
/** BranchGroup between trans and all direct manipulation
* Data depictions */
// WLH 13 March 2000
// private BranchGroup direct = null;
// WLH 10 March 2000
private OrderedGroup non_direct = null;
/** TransformGroup for ViewPlatform */
private TransformGroup vpTrans = null;
/** MouseBehaviorJ3D */
private MouseBehaviorJ3D mouse = null;
/** KeyboardBehaviorJ3D */
private KeyboardBehaviorJ3D keyboard = null;
/** color of box and cursor */
private ColoringAttributes box_color = null;
private ColoringAttributes cursor_color = null;
/** background attached to root */
private Background background = null;
/** TransformGroup between trans and cursor */
private TransformGroup cursor_trans = null;
/** single Switch between cursor_trans and cursor */
private Switch cursor_switch = null;
/** children of cursor_switch */
private BranchGroup cursor_on = null, cursor_off = null;
/** on / off state of cursor */
private boolean cursorOn = false;
/** on / off state of direct manipulation location display */
private boolean directOn = false;
/** single Switch between trans and box */
private Switch box_switch = null;
/** children of box_switch */
private BranchGroup box_on = null, box_off = null;
/** on / off state of box */
private boolean boxOn = false;
/** single Switch between trans and scales */
private Switch scale_switch = null;
/** children of scale_switch */
private BranchGroup scale_on = null, scale_off = null;
/** Vector of screen based AxisScales */
private Vector axis_vector = new Vector();
/** on / off state of cursor in GraphicsModeControl */
/** Vector of DirectManipulationRenderers */
private Vector directs = new Vector();
/** cursor location */
private float cursorX, cursorY, cursorZ;
/** normalized direction perpendicular to current cursor plane */
private float line_x, line_y, line_z;
/** start value for cursor */
private float point_x, point_y, point_z;
/** ModelClip stuff, done by reflection */
private Method modelClipSetEnable = null;
private Method modelClipSetPlane = null;
private Method modelClipAddScope = null;
private Object modelClip = null;
private boolean[] modelClipEnables =
{false, false, false, false, false, false};
public DisplayRendererJ3D () {
super();
}
// WLH 17 Dec 2001
public void destroy() {
not_destroyed = null;
if (canvas != null) canvas.stop();
if (mouse != null) mouse.destroy();
if (root != null) {
root.detach();
root = null;
}
axis_vector.removeAllElements();
directs.removeAllElements();
screen_locked = null;
locked_trans = null;
trans = null;
vpTrans = null;
non_direct = null;
view = null;
canvas = null;
mouse = null;
box_color = null;
cursor_color = null;
background = null;
cursor_trans = null;
cursor_switch = null;
cursor_on = null;
cursor_off = null;
box_switch = null;
box_on = null;
box_off = null;
scale_switch = null;
scale_on = null;
scale_off = null;
}
/**
* Specify <CODE>DisplayImpl</CODE> to be rendered.
* @param dpy <CODE>Display</CODE> to render.
* @exception VisADException If a <CODE>DisplayImpl</CODE> has already
* been specified.
*/
public void setDisplay(DisplayImpl dpy)
throws VisADException
{
if (not_destroyed == null) return;
super.setDisplay(dpy);
dpy.addRendererSourceListener(this);
boxOn = getRendererControl().getBoxOn();
}
public View getView() {
return view;
}
public TransformGroup getViewTrans() {
return vpTrans;
}
/**
* Get the canvas for this renderer
* @return <CODE>VisADCanvasJ3D</CODE> that this renderer uses.
*/
public VisADCanvasJ3D getCanvas() {
return canvas;
}
/**
* Capture the display rendition as an image.
* @return image of the display.
*/
public BufferedImage getImage() {
if (not_destroyed == null) return null;
BufferedImage image = null;
canvas.captureImage = null;
ProjectionControl proj = getDisplay().getProjectionControl();
double[] matrix= proj.getMatrix();
while (image == null) {
try {
synchronized (this) {
canvas.setDoubleBufferEnable(false);
canvas.captureFlag = true;
hasNotifyBeenCalled = false;
if (canvas.getOffscreen()) {
try {
Method renderMethod =
Canvas3D.class.getMethod("renderOffScreenBuffer",
new Class[] {});
renderMethod.invoke(canvas, new Object[] {});
/* Method waitMethod =
Canvas3D.class.getMethod("waitForOffScreenRendering", new Class[] {});
waitMethod.invoke(canvas, new Object[] {});*/
}
catch (NoSuchMethodException e) {}
catch (IllegalAccessException e) {}
catch (InvocationTargetException e) {}
}
try {
proj.setMatrix(matrix);
} catch (RemoteException e) {
e.printStackTrace();
} catch (VisADException e) {
e.printStackTrace();
}
//Make sure the notify has not been called. There is the possbility that the above renderOffScreenBuffer call
//gets completed before we get to this wait, resulting in a starvation lockup here because the canvas already
//notifies the display renderer and when we get to the wait nothing is going to notify this object.
image = canvas.captureImage;
if(image == null && !hasNotifyBeenCalled) {
waitingOnImageCapture = true;
wait();
waitingOnImageCapture = false;
}
}
} catch(InterruptedException e) {
// note notify generates a normal return from wait rather
// than an Exception - control doesn't normally come here
canvas.setDoubleBufferEnable(true); //- just in case
e.printStackTrace();
}
if(image==null) {
image = canvas.captureImage;
}
canvas.captureImage = null;
canvas.setDoubleBufferEnable(true);
if(image == null) {
//What do we do here?
// break?;
}
}
return image;
}
/** used for doing offscreen capture to prevent a starvation lockup */
private boolean hasNotifyBeenCalled = false;
/** used for doing offscreen capture to prevent the extra notify */
private boolean waitingOnImageCapture = false;
void notifyCapture() {
hasNotifyBeenCalled = true;
if(waitingOnImageCapture) {
waitingOnImageCapture = false;
synchronized (this) {
notify();
}
} else {
}
// }
}
public BranchGroup getRoot() {
return root;
}
/**
* Internal method used to initialize newly created
* <CODE>RendererControl</CODE> with current renderer settings
* before it is actually connected to the renderer. This
* means that changes will not generate <CODE>MonitorEvent</CODE>s.
* @param ctl RendererControl to initialize
*/
public void initControl(RendererControl ctl)
{
if (not_destroyed == null) return;
Color3f c3f = new Color3f();
// initialize box colors
if (box_color != null) {
box_color.getColor(c3f);
try {
ctl.setBoxColor(c3f.x, c3f.y, c3f.z);
} catch (Throwable t) {
// ignore any initialization problems
}
}
// initialize cursor colors
if (cursor_color != null) {
cursor_color.getColor(c3f);
try {
ctl.setCursorColor(c3f.x, c3f.y, c3f.z);
} catch (Throwable t) {
// ignore any initialization problems
}
}
// initialize background colors
if (background != null) {
background.getColor(c3f);
try {
ctl.setBackgroundColor(c3f.x, c3f.y, c3f.z);
} catch (Throwable t) {
// ignore any initialization problems
}
}
// initialize box visibility
try {
ctl.setBoxOn(boxOn);
} catch (Throwable t) {
// ignore any initialization problems
}
}
/**
* Update internal values from those in the <CODE>RendererControl</CODE>.
* @param evt <CODE>ControlEvent</CODE> generated by a change to the
* <CODE>RendererControl</CODE>
*/
public void controlChanged(ControlEvent evt)
{
if (not_destroyed == null) return;
RendererControl ctl = (RendererControl )evt.getControl();
float[] ct;
Color3f c3f = new Color3f();
// update box colors
if (box_color != null) {
ct = ctl.getBoxColor();
box_color.getColor(c3f);
if (!Util.isApproximatelyEqual(ct[0], c3f.x) ||
!Util.isApproximatelyEqual(ct[1], c3f.y) ||
!Util.isApproximatelyEqual(ct[2], c3f.z))
{
box_color.setColor(ct[0], ct[1], ct[2]);
}
}
// update cursor colors
if (cursor_color != null) {
ct = ctl.getCursorColor();
cursor_color.getColor(c3f);
if (!Util.isApproximatelyEqual(ct[0], c3f.x) ||
!Util.isApproximatelyEqual(ct[1], c3f.y) ||
!Util.isApproximatelyEqual(ct[2], c3f.z))
{
cursor_color.setColor(ct[0], ct[1], ct[2]);
}
}
// update background colors
ct = ctl.getBackgroundColor();
background.getColor(c3f);
if (!Util.isApproximatelyEqual(ct[0], c3f.x) ||
!Util.isApproximatelyEqual(ct[1], c3f.y) ||
!Util.isApproximatelyEqual(ct[2], c3f.z))
{
background.setColor(ct[0], ct[1], ct[2]);
}
// update box visibility
boolean on = ctl.getBoxOn();
if (on != boxOn) {
boxOn = on;
box_switch.setWhichChild(boxOn ? 1 : 0);
}
}
public TransformGroup getTrans() {
return trans;
}
public BranchGroup getCursorOnBranch() {
return cursor_on;
}
public BranchGroup getBoxOnBranch() {
return box_on;
}
/**
* Toggle the cursor in the display
* @param on true to display the cursor, false to hide it.
*/
public void setCursorOn(boolean on) {
if (not_destroyed == null) return;
cursorOn = on;
if (on) {
cursor_switch.setWhichChild(1); // set cursor on
setCursorStringVector();
}
else {
cursor_switch.setWhichChild(0); // set cursor off
setCursorStringVector(null);
}
}
/**
* Set the flag for direct manipulation
* @param on true for enabling direct manipulation, false to disable
*/
public void setDirectOn(boolean on) {
if (not_destroyed == null) return;
directOn = on;
if (!on) {
setCursorStringVector(null);
}
}
/* WLH 13 March 2000
public BranchGroup getDirect() {
return direct;
}
*/
/**
* Create scene graph root, if none exists, with Transform
* and direct manipulation root;
* create special graphics (e.g., 3-D box, SkewT background),
* any lights, any user interface embedded in scene.
* @param v
* @param vpt
* @param c
* @return Scene graph root.
*/
public abstract BranchGroup createSceneGraph(View v, TransformGroup vpt,
VisADCanvasJ3D c);
/** @deprecated use createBasicSceneGraph(View v, TransformGroup vpt,
VisADCanvasJ3D c, MouseBehaviorJ3D m, ColoringAttributes bc,
ColoringAttributes cc)
instead */
public BranchGroup createBasicSceneGraph(View v, TransformGroup vpt,
VisADCanvasJ3D c, MouseBehaviorJ3D m) {
if (not_destroyed == null) return null;
box_color = new ColoringAttributes();
box_color.setCapability(ColoringAttributes.ALLOW_COLOR_READ);
box_color.setCapability(ColoringAttributes.ALLOW_COLOR_WRITE);
cursor_color = new ColoringAttributes();
cursor_color.setCapability(ColoringAttributes.ALLOW_COLOR_READ);
cursor_color.setCapability(ColoringAttributes.ALLOW_COLOR_WRITE);
return createBasicSceneGraph(v, vpt, c, m, box_color, cursor_color);
}
/**
* Create scene graph root, if none exists, with Transform
* and direct manipulation root.
* @param v
* @param vpt
* @param c
* @param m
* @return Scene graph root.
*/
public BranchGroup createBasicSceneGraph(View v, TransformGroup vpt,
VisADCanvasJ3D c, MouseBehaviorJ3D m, ColoringAttributes bc,
ColoringAttributes cc) {
if (root != null) return root;
if (not_destroyed == null) return null;
mouse = m;
view = v;
vpTrans = vpt;
box_color = bc;
cursor_color = cc;
// WLH 14 April 98
v.setDepthBufferFreezeTransparent(false);
canvas = c;
// Create the root of the branch graph
root = new BranchGroup();
setSceneGraphObjectName(root, "Root");
root.setCapability(BranchGroup.ALLOW_DETACH);
root.setCapability(Group.ALLOW_CHILDREN_READ);
root.setCapability(Group.ALLOW_CHILDREN_WRITE);
root.setCapability(Group.ALLOW_CHILDREN_EXTEND);
// create the TransformGroup that is the parent of
// Data object Group objects
setTransform3D(null);
root.addChild(trans);
// create background
background = new Background();
setSceneGraphObjectName(background, "Background");
background.setCapability(Background.ALLOW_COLOR_WRITE);
background.setCapability(Background.ALLOW_COLOR_READ);
float[] ctlBg = getRendererControl().getBackgroundColor();
background.setColor(ctlBg[0], ctlBg[1], ctlBg[2]);
BoundingSphere bound2 = new BoundingSphere(new Point3d(0.0,0.0,0.0),2000000.0);
background.setApplicationBounds(bound2);
root.addChild(background);
/* WLH 13 April 99 - does nothing
BoundingBox boundingbox =
new BoundingBox(new Point3d(-1.0, -1.0, -1.0),
new Point3d(1.0, 1.0, 1.0));
trans.addChild(new BoundingLeaf(boundingbox));
*/
/* WLH 13 Macrh 2000
// create the BranchGroup that is the parent of direct
// manipulation Data object BranchGroup objects
direct = new BranchGroup();
direct.setCapability(Group.ALLOW_CHILDREN_READ);
direct.setCapability(Group.ALLOW_CHILDREN_WRITE);
direct.setCapability(Group.ALLOW_CHILDREN_EXTEND);
direct.setCapability(Node.ENABLE_PICK_REPORTING);
trans.addChild(direct);
*/
// WLH 10 March 2000
non_direct = new OrderedGroup();
setSceneGraphObjectName(non_direct, "NonDirect");
non_direct.setCapability(Group.ALLOW_CHILDREN_READ);
non_direct.setCapability(Group.ALLOW_CHILDREN_WRITE);
non_direct.setCapability(Group.ALLOW_CHILDREN_EXTEND);
non_direct.setCapability(Node.ENABLE_PICK_REPORTING);
trans.addChild(non_direct);
cursor_trans = new TransformGroup();
setSceneGraphObjectName(cursor_trans, "CursorTrans");
cursor_trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
cursor_trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
cursor_trans.setCapability(Group.ALLOW_CHILDREN_READ);
cursor_trans.setCapability(Group.ALLOW_CHILDREN_WRITE);
cursor_trans.setCapability(Group.ALLOW_CHILDREN_EXTEND);
trans.addChild(cursor_trans);
cursor_switch = new Switch();
setSceneGraphObjectName(cursor_switch, "CursorSwitch");
cursor_switch.setCapability(Switch.ALLOW_SWITCH_READ);
cursor_switch.setCapability(Switch.ALLOW_SWITCH_WRITE);
cursor_switch.setCapability(Group.ALLOW_CHILDREN_READ);
cursor_trans.addChild(cursor_switch);
cursor_on = new BranchGroup();
setSceneGraphObjectName(cursor_on, "CursorOn");
cursor_on.setCapability(Group.ALLOW_CHILDREN_READ);
cursor_on.setCapability(Group.ALLOW_CHILDREN_WRITE);
cursor_off = new BranchGroup();
setSceneGraphObjectName(cursor_off, "CursorOff");
cursor_off.setCapability(Group.ALLOW_CHILDREN_READ);
cursor_switch.addChild(cursor_off);
cursor_switch.addChild(cursor_on);
cursor_switch.setWhichChild(0); // initially off
cursorOn = false;
box_switch = new Switch();
setSceneGraphObjectName(box_switch, "BoxSwitch");
box_switch.setCapability(Switch.ALLOW_SWITCH_READ);
box_switch.setCapability(Switch.ALLOW_SWITCH_WRITE);
box_switch.setCapability(Group.ALLOW_CHILDREN_READ);
trans.addChild(box_switch);
box_on = new BranchGroup();
setSceneGraphObjectName(box_on, "BoxOn");
box_on.setCapability(Group.ALLOW_CHILDREN_READ);
box_on.setCapability(Group.ALLOW_CHILDREN_WRITE);
box_off = new BranchGroup();
setSceneGraphObjectName(box_off, "BoxOff");
box_off.setCapability(Group.ALLOW_CHILDREN_READ);
box_switch.addChild(box_off);
box_switch.addChild(box_on);
box_switch.setWhichChild(1); // initially on
try {
setBoxOn(true);
} catch (Exception e) {
}
scale_switch = new Switch();
setSceneGraphObjectName(scale_switch, "ScaleSwitch");
scale_switch.setCapability(Switch.ALLOW_SWITCH_READ);
scale_switch.setCapability(Switch.ALLOW_SWITCH_WRITE);
scale_switch.setCapability(Group.ALLOW_CHILDREN_READ);
trans.addChild(scale_switch);
scale_on = new BranchGroup();
setSceneGraphObjectName(scale_on, "ScaleOn");
scale_on.setCapability(Group.ALLOW_CHILDREN_READ);
scale_on.setCapability(Group.ALLOW_CHILDREN_WRITE);
scale_on.setCapability(Group.ALLOW_CHILDREN_EXTEND);
scale_off = new BranchGroup();
setSceneGraphObjectName(scale_off, "ScaleOff");
scale_off.setCapability(Group.ALLOW_CHILDREN_READ);
scale_switch.addChild(scale_off);
scale_switch.addChild(scale_on);
scale_switch.setWhichChild(0); // initially off
// WLH 23 Oct 2001
try {
Class modelClipClass = Class.forName("javax.media.j3d.ModelClip");
Class[] param = new Class[] {};
Constructor modelClipConstructor = modelClipClass.getConstructor(param);
param = new Class[] {int.class, boolean.class};
modelClipSetEnable = modelClipClass.getMethod("setEnable", param);
param = new Class[] {int.class, javax.vecmath.Vector4d.class};
modelClipSetPlane = modelClipClass.getMethod("setPlane", param);
param = new Class[] {javax.media.j3d.Group.class};
modelClipAddScope = modelClipClass.getMethod("addScope", param);
param = new Class[] {int.class};
Method modelClipSetCapability =
modelClipClass.getMethod("setCapability", param);
param = new Class[] {javax.media.j3d.Bounds.class};
Method modelClipSetInfluencingBounds =
modelClipClass.getMethod("setInfluencingBounds", param);
modelClip = modelClipConstructor.newInstance(new Object[] {});
int ALLOW_PLANE_WRITE =
modelClipClass.getField("ALLOW_PLANE_WRITE").getInt(modelClip);
modelClipSetCapability.invoke(modelClip,
new Object[] {new Integer(ALLOW_PLANE_WRITE)});
int ALLOW_ENABLE_WRITE =
modelClipClass.getField("ALLOW_ENABLE_WRITE").getInt(modelClip);
modelClipSetCapability.invoke(modelClip,
new Object[] {new Integer(ALLOW_ENABLE_WRITE)});
Boolean f = new Boolean(false);
for (int i=0; i<6; i++) {
modelClipSetEnable.invoke(modelClip, new Object[] {new Integer(i), f});
}
BoundingSphere bound3 =
new BoundingSphere(new Point3d(0.0,0.0,0.0),2000000.0);
modelClipSetInfluencingBounds.invoke(modelClip, new Object[] {bound3});
background.setApplicationBounds(bound2);
modelClipAddScope.invoke(modelClip, new Object[] {non_direct});
setSceneGraphObjectName(((Node) modelClip), "ModelClip");
trans.addChild((Node) modelClip);
}
catch (ClassNotFoundException e) {
}
catch (NoSuchMethodException e) {
}
catch (InstantiationException e) {
}
catch (IllegalAccessException e) {
}
catch (InvocationTargetException e) {
}
catch (NoSuchFieldException e) {
}
return root;
}
// WLH 23 Oct 2001
/**
* Define a clipping plane in (XAxis, YAxis, ZAxis) space. Allows
* up to 6 arbitrary planes. Each clip plane is defined by the equation:
* <PRE>
* aX + bY + cZ + d <= 0
* </PRE>
* <p>Example useage:</p>
* To clip to the usual VisAD cube (i.e., x, y and z values in the
* range -1.0 to +1.0) (see Test35.java), call:
* <PRE>
* DisplayRendererJ3D dr =
* (DisplayRendererJ3D) display.getDisplayRenderer();
* dr.setClip(0, true, 1.0f, 0.0f, 0.0f, -1.01f); // X_POS face
* dr.setClip(1, true, -1.0f, 0.0f, 0.0f, -1.01f); // X_NEG face
* dr.setClip(2, true, 0.0f, 1.0f, 0.0f, -1.01f); // Y_POS face
* dr.setClip(3, true, 0.0f, -1.0f, 0.0f, -1.01f); // Y_NEG face
* dr.setClip(4, true, 0.0f, 0.0f, 1.0f, -1.01f); // Z_POS face
* dr.setClip(5, true, 0.0f, 0.0f, -1.0f, -1.01f); // Z_NEG face
* </PRE>
* <b>Note:</b> d value is slightly less than -1.0 so items in the plane
* are not clipped.
* @param plane plane number must be in (0, ..., 5)).
* @param enable true to enable clipping on this plane, false to disable
* @param a x coefficent
* @param b y coefficent
* @param c z coefficent
* @param d constant
* @throws VisADException illegal plane argument or
* unsupported (< 1.2) version of Java 3D
*/
public void setClip(int plane, boolean enable, float a, float b, float c, float d)
throws VisADException {
if (not_destroyed == null) return;
if (plane < 0 || 5 < plane) {
throw new DisplayException("plane must be in 0,...,5 range " + plane);
}
if (modelClip == null ||
modelClipSetEnable == null ||
modelClipSetPlane == null) {
throw new DisplayException("model clipping not supported in this " +
"version of Java3D");
}
Vector4d vect = new Vector4d((double) a, (double) b, (double) c, (double) d);
try {
Object[] params = {new Integer(plane), new Boolean(enable)};
modelClipSetEnable.invoke(modelClip, params);
params = new Object[] {new Integer(plane), vect};
modelClipSetPlane.invoke(modelClip, params);
modelClipEnables[plane] = enable;
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
}
private void clipOff() {
if (not_destroyed == null) return;
try {
for (int i=0; i<6; i++) {
if (modelClipEnables[i]) {
Object[] params = {new Integer(i), new Boolean(false)};
modelClipSetEnable.invoke(modelClip, params);
}
}
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
}
private void clipOn() {
if (not_destroyed == null) return;
try {
for (int i=0; i<6; i++) {
if (modelClipEnables[i]) {
Object[] params = {new Integer(i), new Boolean(true)};
modelClipSetEnable.invoke(modelClip, params);
}
}
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* Get the <CODE>MouseBehavior</CODE> associated with this renderer.
* @return the <CODE>MouseBehavior</CODE> used by this renderer to handle
* mouse events.
*/
public MouseBehavior getMouseBehavior() {
return mouse;
}
/**
* Get the <CODE>KeyboardBehavior</CODE> associated with this renderer.
*
* @return the <CODE>KeyboardBehavior</CODE> used by this renderer to handle
* mouse events.
*/
public KeyboardBehavior getKeyboardBehavior() {
return keyboard;
}
public void addSceneGraphComponent(Group group) {
if (not_destroyed == null) return;
non_direct.addChild(group);
}
public void addLockedSceneGraphComponent(Group group) {
if (not_destroyed == null || screen_locked == null) return;
screen_locked.addChild(group);
}
//- TDR, Hydra stuff
public void addLockedSceneGraphComponent(Group group, boolean initWithProj) {
if (not_destroyed == null || screen_locked == null) return;
if (initWithProj) {
ProjectionControl proj = getDisplay().getProjectionControl();
locked_trans.setTransform(new Transform3D(proj.getMatrix()));
}
screen_locked.addChild(group);
}
public void updateLockedTrans(double[] matrix) {
if (locked_trans != null) {
locked_trans.setTransform(new Transform3D(matrix));
}
}
public void addDirectManipulationSceneGraphComponent(Group group,
DirectManipulationRendererJ3D renderer) {
if (not_destroyed == null) return;
// WLH 13 March 2000
// direct.addChild(group);
non_direct.addChild(group);
directs.addElement(renderer);
}
public void clearScene(DataRenderer renderer) {
if (not_destroyed == null) return;
directs.removeElement(renderer);
}
/**
* Get the cusor location.
* @return cursor location as an array of x, y, and z values
*/
public double[] getCursor() {
double[] cursor = new double[3];
cursor[0] = cursorX;
cursor[1] = cursorY;
cursor[2] = cursorZ;
return cursor;
}
public void depth_cursor(VisADRay ray) {
line_x = (float) ray.vector[0];
line_y = (float) ray.vector[1];
line_z = (float) ray.vector[2];
point_x = cursorX;
point_y = cursorY;
point_z = cursorZ;
}
public void drag_depth(float diff) {
if (not_destroyed == null) return;
cursorX = point_x + diff * line_x;
cursorY = point_y + diff * line_y;
cursorZ = point_z + diff * line_z;
setCursorLoc();
}
public void drag_cursor(VisADRay ray, boolean first) {
if (not_destroyed == null) return;
float o_x = (float) ray.position[0];
float o_y = (float) ray.position[1];
float o_z = (float) ray.position[2];
float d_x = (float) ray.vector[0];
float d_y = (float) ray.vector[1];
float d_z = (float) ray.vector[2];
/*
Point3d origin = new Point3d();
Vector3d direction = new Vector3d();
ray.get(origin, direction);
float o_x = (float) origin.x;
float o_y = (float) origin.y;
float o_z = (float) origin.z;
float d_x = (float) direction.x;
float d_y = (float) direction.y;
float d_z = (float) direction.z;
*/
if (first) {
line_x = d_x;
line_y = d_y;
line_z = d_z;
}
float dot = (cursorX - o_x) * line_x +
(cursorY - o_y) * line_y +
(cursorZ - o_z) * line_z;
float dot2 = d_x * line_x + d_y * line_y + d_z * line_z;
if (dot2 == 0.0) return;
dot = dot / dot2;
// new cursor location is intersection
cursorX = o_x + dot * d_x;
cursorY = o_y + dot * d_y;
cursorZ = o_z + dot * d_z;
setCursorLoc();
}
private void setCursorLoc() {
if (not_destroyed == null) return;
Transform3D t = new Transform3D();
t.setTranslation(new Vector3f(cursorX, cursorY, cursorZ));
cursor_trans.setTransform(t);
if (cursorOn) {
setCursorStringVector();
}
}
/**
* Set the cursor location
* @param x x location
* @param y y location
* @param z z location
*/
public void setCursorLoc(float x, float y, float z) {
if (not_destroyed == null) return;
Transform3D t = new Transform3D();
t.setTranslation(new Vector3f(x, y, z));
cursor_trans.setTransform(t);
if (cursorOn) {
setCursorStringVector();
}
}
/**
* Whenever <CODE>cursorOn</CODE> or <CODE>directOn</CODE> is true,
* display Strings in cursorStringVector.
* @param canvas
*/
public void drawCursorStringVector(VisADCanvasJ3D canvas) {
if (not_destroyed == null) return;
GraphicsContext3D graphics = canvas.getGraphicsContext3D();
// graphics.setModelClip(null);
// causes NullPointerException at GraphicsContext3D.java:689
// set cursor color, if possible
try {
float[] c3 = getCursorColor();
Appearance appearance = new Appearance();
ColoringAttributes color = new ColoringAttributes();
color.setColor(new Color3f(c3));
appearance.setColoringAttributes(color);
graphics.setAppearance(appearance);
} catch (Exception e) {
}
Point3d position1 = new Point3d();
Point3d position2 = new Point3d();
Point3d position3 = new Point3d();
canvas.getPixelLocationInImagePlate(1, 10, position1);
canvas.getPixelLocationInImagePlate(10, 10, position2);
canvas.getPixelLocationInImagePlate(1, 1, position3);
DisplayImpl display = getDisplay();
if (display != null && display.getGraphicsModeControl() != null) {
// hack to move text closer to eye
if (getDisplay().getGraphicsModeControl().getProjectionPolicy() ==
View.PERSPECTIVE_PROJECTION) {
Point3d left_eye = new Point3d();
Point3d right_eye = new Point3d();
canvas.getLeftEyeInImagePlate(left_eye);
canvas.getRightEyeInImagePlate(right_eye);
Point3d eye = new Point3d((left_eye.x + right_eye.x)/2.0,
(left_eye.y + right_eye.y)/2.0,
(left_eye.z + right_eye.z)/2.0);
double alpha = 0.3;
position1.x = alpha * position1.x + (1.0 - alpha) * eye.x;
position1.y = alpha * position1.y + (1.0 - alpha) * eye.y;
position1.z = alpha * position1.z + (1.0 - alpha) * eye.z;
position2.x = alpha * position2.x + (1.0 - alpha) * eye.x;
position2.y = alpha * position2.y + (1.0 - alpha) * eye.y;
position2.z = alpha * position2.z + (1.0 - alpha) * eye.z;
position3.x = alpha * position3.x + (1.0 - alpha) * eye.x;
position3.y = alpha * position3.y + (1.0 - alpha) * eye.y;
position3.z = alpha * position3.z + (1.0 - alpha) * eye.z;
}
}
// end of hack to move text closer to eye
Transform3D t = new Transform3D();
canvas.getImagePlateToVworld(t);
t.transform(position1);
t.transform(position2);
t.transform(position3);
// draw cursor strings in upper left corner of screen
double[] start = {(double) position1.x,
(double) position1.y,
(double) position1.z};
double[] base = {(double) (position2.x - position1.x),
(double) (position2.y - position1.y),
(double) (position2.z - position1.z)};
double[] up = {(double) (position3.x - position1.x),
(double) (position3.y - position1.y),
(double) (position3.z - position1.z)};
if (cursorOn || directOn) {
Enumeration strings = getCursorStringVector().elements();
while (strings.hasMoreElements()) {
String string = (String) strings.nextElement();
if ((string != null) && (! string.trim().isEmpty())) {
try {
VisADLineArray array =
PlotText.render_label(string, start, base, up, false);
graphics.draw(((DisplayImplJ3D) getDisplay()).makeGeometry(array));
start[1] -= 1.2 * up[1];
}
catch (VisADException e) {
}
}
}
}
// draw Exception strings in lower left corner of screen
double[] startl = {(double) position3.x,
(double) -position3.y,
(double) position3.z};
Vector rendererVector = getDisplay().getRendererVector();
Enumeration renderers = rendererVector.elements();
while (renderers.hasMoreElements()) {
DataRenderer renderer = (DataRenderer) renderers.nextElement();
Vector exceptionVector = renderer.getExceptionVector();
Enumeration exceptions = exceptionVector.elements();
while (exceptions.hasMoreElements()) {
Exception error = (Exception) exceptions.nextElement();
String string = error.getMessage();
try {
VisADLineArray array =
PlotText.render_label(string, startl, base, up, false);
graphics.draw(((DisplayImplJ3D) getDisplay()).makeGeometry(array));
startl[1] += 1.2 * up[1];
}
catch (VisADException e) {
}
}
}
// draw wait flag in lower left corner of screen
if (getWaitFlag() && getWaitMessageVisible()) {
try {
VisADLineArray array =
PlotText.render_label("please wait . . .", startl, base, up, false);
graphics.draw(((DisplayImplJ3D) getDisplay()).makeGeometry(array));
startl[1] += 1.2 * up[1];
}
catch (VisADException e) {
}
}
// draw Animation string in lower right corner of screen
String[] animation_string = getAnimationString();
if (animation_string[0] != null) {
int nchars = animation_string[0].length();
if (nchars < 12) nchars = 12;
double[] starta = {(double) (-position2.x - nchars *
(position2.x - position1.x)),
(double) -position3.y + 1.2 * up[1],
// (double) position2.y, WLH 30 April 99
(double) position2.z};
try {
VisADLineArray array =
PlotText.render_label(animation_string[0], starta, base, up, false);
graphics.draw(((DisplayImplJ3D) getDisplay()).makeGeometry(array));
starta[1] -= 1.2 * up[1];
if (animation_string[1] != null) {
array =
PlotText.render_label(animation_string[1], starta, base, up, false);
graphics.draw(((DisplayImplJ3D) getDisplay()).makeGeometry(array));
starta[1] -= 1.2 * up[1];
}
}
catch (VisADException e) {
}
}
if (scale_switch != null && scale_switch.getWhichChild() == 1) {
Dimension d = canvas.getSize();
int w = d.width;
int h = d.height;
double MUL = 3.0 * w / 256.0;
double XMAX = Math.abs(MUL * position2.x - (MUL - 1.0) * position3.x);
double YMAX = Math.abs(MUL * position2.y - (MUL - 1.0) * position3.y);
double XMIN = -XMAX;
double YMIN = -YMAX;
TransformGroup trans = getTrans();
Transform3D tt = new Transform3D();
trans.getTransform(tt);
tt.invert();
Point3d positionx = new Point3d(XMAX, YMAX, 0.0);
Point3d positionn = new Point3d(XMIN, YMIN, 0.0);
tt.transform(positionx);
tt.transform(positionn);
double XTMAX = positionx.x;
double YTMAX = positionx.y;
double XTMIN = positionn.x;
double YTMIN = positionn.y;
Enumeration axes = axis_vector.elements();
while (axes.hasMoreElements()) {
AxisScale axisScale = (AxisScale) axes.nextElement();
try {
boolean success =
axisScale.makeScreenBasedScale(XMIN, YMIN, XMAX, YMAX,
XTMIN, YTMIN, XTMAX, YTMAX);
if (success) {
// System.out.println("makeScreenBasedScale success");
int axis = axisScale.getAxis();
int axis_ordinal = axisScale.getAxisOrdinal();
VisADLineArray array = axisScale.getScaleArray();
VisADTriangleArray labels = axisScale.getLabelArray();
float[] scale_color = axisScale.getColor().getColorComponents(null);
// set cursor color, if possible
Appearance appearance = new Appearance();
ColoringAttributes color = new ColoringAttributes();
color.setColor(new Color3f(scale_color));
appearance.setColoringAttributes(color);
graphics.setAppearance(appearance);
graphics.draw(((DisplayImplJ3D) getDisplay()).makeGeometry(array));
if (labels != null) {
GeometryArray labelGeometry =
((DisplayImplJ3D) getDisplay()).makeGeometry(labels);
Appearance labelAppearance =
ShadowTypeJ3D.staticMakeAppearance(
getDisplay().getGraphicsModeControl(), null, null,
labelGeometry, true);
graphics.setAppearance(labelAppearance);
graphics.draw(labelGeometry);
}
}
else {
// System.out.println("makeScreenBasedScale fail");
}
} catch (Exception e) {
}
}
}
// graphics.flush(true); doesn't help
// clipOn(); doesn't work
}
/**
* Find the <CODE>DataRenderer</CODE> that is closest to the ray and
* uses the specified mouse modifiers for direct manipulation.
* @param ray position to check
* @param mouseModifiers modifiers for mouse clicks
* @return closest DataRenderer that uses the specified mouse click
* modifiers for direct manipulation or null if there is none.
*/
public DataRenderer findDirect(VisADRay ray, int mouseModifiers) {
if (not_destroyed == null) return null;
DirectManipulationRendererJ3D renderer = null;
float distance = Float.MAX_VALUE;
Enumeration renderers = ((Vector) directs.clone()).elements();
while (renderers.hasMoreElements()) {
DirectManipulationRendererJ3D r =
(DirectManipulationRendererJ3D) renderers.nextElement();
if (r.getEnabled()) {
r.setLastMouseModifiers(mouseModifiers);
float d = r.checkClose(ray.position, ray.vector);
if (d < distance) {
distance = d;
renderer = r;
}
}
}
if (distance < getPickThreshhold()) {
return renderer;
}
else {
return null;
}
}
/**
* Check to see if there are any <CODE>DirectManipulationRenderer</CODE>s
* in this display.
* @return true if there are any
*/
public boolean anyDirects() {
if (not_destroyed == null) return false;
return !directs.isEmpty();
}
/**
* Set the scales on.
* @param on turn on if true, otherwise turn them off
*/
public void setScaleOn(boolean on) {
if (not_destroyed == null) return;
if (on) {
scale_switch.setWhichChild(1); // on
}
else {
scale_switch.setWhichChild(0); // off
}
}
/**
* Set the scale for the appropriate axis.
* @param axisScale AxisScale for this scale
* @throws VisADException couldn't set the scale
*/
public void setScale(AxisScale axisScale)
throws VisADException {
if (not_destroyed == null) return;
if (axisScale.getScreenBased() && getMode2D()) {
if (!axis_vector.contains(axisScale)) {
axis_vector.addElement(axisScale);
clearScale(axisScale);
/* Replaced by clearScale() 2001-08-08 DRM
// eliminate any non-screen-based scale for this AxisScale
int axis = axisScale.getAxis();
int axis_ordinal = axisScale.getAxisOrdinal();
int dim = getMode2D() ? 2 : 3;
synchronized (scale_on) {
int n = scale_on.numChildren();
int m = dim * axis_ordinal + axis;
if (m >= n) {
for (int i=n; i<=m; i++) {
BranchGroup empty = new BranchGroup();
empty.setCapability(BranchGroup.ALLOW_DETACH);
empty.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
scale_on.addChild(empty);
}
}
BranchGroup empty = new BranchGroup();
empty.setCapability(BranchGroup.ALLOW_DETACH);
empty.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
scale_on.setChild(empty, m);
}
*/
}
}
else {
setScale(axisScale.getAxis(),
axisScale.getAxisOrdinal(),
axisScale.getScaleArray(),
axisScale.getLabelArray(),
axisScale.getColor().getColorComponents(null));
}
}
/**
* Set the scale for the appropriate axis.
* @param axis axis for this scale (0 = XAxis, 1 = YAxis, 2 = ZAxis)
* @param axis_ordinal position along the axis
* @param array <CODE>VisADLineArray</CODE> representing the scale plot
* @param scale_color array (dim 3) representing the red, green and blue
* color values.
* @throws VisADException couldn't set the scale
*/
public void setScale(int axis, int axis_ordinal,
VisADLineArray array, float[] scale_color)
throws VisADException {
if (not_destroyed == null) return;
setScale(axis, axis_ordinal, array, null, scale_color);
}
/**
* Set the scale for the appropriate axis.
* @param axis axis for this scale (0 = XAxis, 1 = YAxis, 2 = ZAxis)
* @param axis_ordinal position along the axis
* @param array <CODE>VisADLineArray</CODE> representing the scale plot
* @param labels <CODE>VisADTriangleArray</CODE> representing the labels
* created using a font (can be null)
* @param scale_color array (dim 3) representing the red, green and blue
* color values.
* @throws VisADException couldn't set the scale
*/
public void setScale(int axis, int axis_ordinal,
VisADLineArray array, VisADTriangleArray labels,
float[] scale_color)
throws VisADException {
if (not_destroyed == null) return;
// DisplayImpl.printStack("setScale");
// add array to scale_on
// replace any existing at axis, axis_ordinal
DisplayImplJ3D display = (DisplayImplJ3D) getDisplay();
GeometryArray geometry = display.makeGeometry(array);
GraphicsModeControl mode = display.getGraphicsModeControl();
ColoringAttributes color = new ColoringAttributes();
color.setColor(scale_color[0], scale_color[1], scale_color[2]);
Appearance appearance =
ShadowTypeJ3D.staticMakeAppearance(mode, null, color, geometry, false);
Shape3D shape = new Shape3D(geometry, appearance);
shape.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
shape.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
BranchGroup group = new BranchGroup();
group.setCapability(BranchGroup.ALLOW_DETACH);
group.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
group.addChild(shape);
if (labels != null) {
GeometryArray labelGeometry = display.makeGeometry(labels);
Appearance labelAppearance =
ShadowTypeJ3D.staticMakeAppearance(mode, null, null,
labelGeometry, true);
Shape3D labelShape = new Shape3D(labelGeometry, labelAppearance);
labelShape.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
labelShape.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
group.addChild(labelShape);
if (labels instanceof VisADTriangleArray) {
GeometryArray labelGeometry2 = display.makeGeometry(labels);
Appearance labelAppearance2 =
ShadowTypeJ3D.staticMakeAppearance(mode, null, null,
labelGeometry2, true);
// LineAttributes la = labelAppearance2.getLineAttributes();
// better without anti-aliasing
// la.setLineAntialiasingEnable(true);
PolygonAttributes pa = labelAppearance2.getPolygonAttributes();
pa.setPolygonMode(PolygonAttributes.POLYGON_LINE);
Shape3D labelShape2 = new Shape3D(labelGeometry2, labelAppearance2);
labelShape2.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
labelShape2.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
group.addChild(labelShape2);
}
}
// may only add BranchGroup to 'live' scale_on
int dim = getMode2D() ? 2 : 3;
synchronized (scale_on) {
int n = scale_on.numChildren();
int m = dim * axis_ordinal + axis;
if (m >= n) {
for (int i=n; i<=m; i++) {
BranchGroup empty = new BranchGroup();
empty.setCapability(BranchGroup.ALLOW_DETACH);
empty.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
scale_on.addChild(empty);
}
}
scale_on.setChild(group, m);
}
}
/**
* Remove all the scales being rendered.
*/
public void clearScales() {
if (not_destroyed == null) return;
if (scale_on != null) {
synchronized (scale_on) {
int n = scale_on.numChildren();
for (int i=n-1; i>=0; i--) {
scale_on.removeChild(i);
}
}
}
axis_vector.removeAllElements();
}
/**
* Remove a particular scale being rendered.
* @param axisScale AxisScale to remove
*/
public void clearScale(AxisScale axisScale) {
if (not_destroyed == null) return;
// eliminate any non-screen-based scale for this AxisScale
int axis = axisScale.getAxis();
int axis_ordinal = axisScale.getAxisOrdinal();
int dim = getMode2D() ? 2 : 3;
synchronized (scale_on) {
int n = scale_on.numChildren();
int m = dim * axis_ordinal + axis;
if (m >= n) {
for (int i=n; i<=m; i++) {
BranchGroup empty = new BranchGroup();
empty.setCapability(BranchGroup.ALLOW_DETACH);
empty.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
scale_on.addChild(empty);
}
}
BranchGroup empty = new BranchGroup();
empty.setCapability(BranchGroup.ALLOW_DETACH);
empty.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
scale_on.setChild(empty, m);
}
}
public void setTransform3D(Transform3D t) {
if (not_destroyed == null) return;
if (trans == null) {
trans = new TransformGroup();
setSceneGraphObjectName(trans, "Trans");
trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
trans.setCapability(Group.ALLOW_CHILDREN_READ);
trans.setCapability(Group.ALLOW_CHILDREN_WRITE);
trans.setCapability(Group.ALLOW_CHILDREN_EXTEND);
}
if (t != null) {
trans.setTransform(t);
if (locked_trans == null && root != null) {
locked_trans = new TransformGroup();
setSceneGraphObjectName(locked_trans, "LockedTrans");
locked_trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
locked_trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
locked_trans.setCapability(Group.ALLOW_CHILDREN_READ);
locked_trans.setCapability(Group.ALLOW_CHILDREN_WRITE);
locked_trans.setCapability(Group.ALLOW_CHILDREN_EXTEND);
locked_trans.setTransform(t);
screen_locked = new OrderedGroup();
setSceneGraphObjectName(screen_locked, "ScreenLocked");
screen_locked.setCapability(Group.ALLOW_CHILDREN_READ);
screen_locked.setCapability(Group.ALLOW_CHILDREN_WRITE);
screen_locked.setCapability(Group.ALLOW_CHILDREN_EXTEND);
screen_locked.setCapability(Node.ENABLE_PICK_REPORTING);
locked_trans.addChild(screen_locked);
BranchGroup bgroup = new BranchGroup();
setSceneGraphObjectName(bgroup, "LockedGroup");
bgroup.setCapability(Group.ALLOW_CHILDREN_READ);
bgroup.setCapability(Group.ALLOW_CHILDREN_WRITE);
bgroup.setCapability(Group.ALLOW_CHILDREN_EXTEND);
bgroup.addChild(locked_trans);
root.addChild(bgroup);
}
}
}
/**
* Factory for constructing a subclass of <CODE>Control</CODE>
* appropriate for the graphics API and for this
* <CODE>DisplayRenderer</CODE>; invoked by <CODE>ScalarMap</CODE>
* when it is <CODE>addMap()</CODE>ed to a <CODE>Display</CODE>.
* @param map The <CODE>ScalarMap</CODE> for which a <CODE>Control</CODE>
* should be built.
* @return The appropriate <CODE>Control</CODE>.
*/
public Control makeControl(ScalarMap map) {
if (not_destroyed == null) return null;
DisplayRealType type = map.getDisplayScalar();
DisplayImplJ3D display = (DisplayImplJ3D) getDisplay();
if (type == null) return null;
if (type.equals(Display.XAxis) ||
type.equals(Display.YAxis) ||
type.equals(Display.ZAxis) ||
type.equals(Display.Latitude) ||
type.equals(Display.Longitude) ||
type.equals(Display.Radius)) {
return (ProjectionControlJ3D) display.getProjectionControl();
}
else if (type.equals(Display.RGB) ||
type.equals(Display.HSV) ||
type.equals(Display.CMY)) {
return new ColorControl(display);
}
else if (type.equals(Display.RGBA)) {
return new ColorAlphaControl(display);
}
else if (type.equals(Display.Animation)) {
// note only one RealType may be mapped to Animation
// so control must be null
Control control = display.getControl(AnimationControlJ3D.class);
if (control != null) return control;
else return new AnimationControlJ3D(display, (RealType) map.getScalar());
}
else if (type.equals(Display.SelectValue)) {
return new ValueControlJ3D(display);
}
else if (type.equals(Display.SelectRange)) {
return new RangeControl(display);
}
else if (type.equals(Display.IsoContour)) {
return new ContourControl(display);
}
else if (type.equals(Display.Flow1X) ||
type.equals(Display.Flow1Y) ||
type.equals(Display.Flow1Z) ||
type.equals(Display.Flow1Elevation) ||
type.equals(Display.Flow1Azimuth) ||
type.equals(Display.Flow1Radial)) {
Control control = display.getControl(Flow1Control.class);
if (control != null) return control;
else return new Flow1Control(display);
}
else if (type.equals(Display.Flow2X) ||
type.equals(Display.Flow2Y) ||
type.equals(Display.Flow2Z) ||
type.equals(Display.Flow2Elevation) ||
type.equals(Display.Flow2Azimuth) ||
type.equals(Display.Flow2Radial)) {
Control control = display.getControl(Flow2Control.class);
if (control != null) return control;
else return new Flow2Control(display);
}
else if (type.equals(Display.Shape)) {
return new ShapeControl(display);
}
else if (type.equals(Display.Text)) {
return new TextControl(display);
}
else {
return null;
}
}
/**
* Create the default <CODE>DataRenderer</CODE> for this type of
* <CODE>DisplayRenderer</CODE>
* @return new default renderer
*/
public DataRenderer makeDefaultRenderer() {
return new DefaultRendererJ3D();
}
/**
* Check if the <CODE>DataRenderer</CODE> in question is legal for this
* <CODE>DisplayRenderer</CODE>
* @param renderer <CODE>DataRenderer</CODE> to check
* @return true if renderer is a subclass of <CODE>RendererJ3D</CODE>
*/
public boolean legalDataRenderer(DataRenderer renderer) {
return (renderer instanceof RendererJ3D);
}
public void rendererDeleted(DataRenderer renderer)
{
if (not_destroyed == null) return;
clearScene(renderer);
}
public void setLineWidth(float width) {
}
/**
* Add a <CODE>KeyboardBehavior</CODE> for keyboard control of rotation,
* translation and zoom.
* @param behavior keyboard behavior to add
*/
public void addKeyboardBehavior(KeyboardBehaviorJ3D behavior)
{
if (not_destroyed == null) return;
BranchGroup bg = new BranchGroup();
bg.setCapability(Group.ALLOW_CHILDREN_READ);
bg.addChild(behavior);
trans.addChild(bg);
}
public void render_trigger() {
ProjectionControl proj = getDisplay().getProjectionControl();
try {
if (proj != null) proj.setMatrix(proj.getMatrix());
}
catch (VisADException e) { }
catch (RemoteException e) { }
}
public void setWaitFlag(boolean b) {
if (not_destroyed == null) return;
boolean old = getWaitFlag();
super.setWaitFlag(b);
if (b != old) {
render_trigger();
}
}
public int getTextureWidthMax() {
return VisADCanvasJ3D.getTextureWidthMax();
}
public int getTextureHeightMax() {
return VisADCanvasJ3D.getTextureWidthMax();
}
}