//
// DisplayRendererJ2D.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.java2d;
import visad.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.AffineTransform;
import java.rmi.*;
import java.util.*;
import java.io.*;
import javax.imageio.*;
import visad.util.Util;
/**
* <CODE>DisplayRendererJ2D</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>DisplayRendererJ2D</CODE> also manages the overall relation of
* <CODE>DataRenderer</CODE> output to Java2D and manages the VisAD 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>DisplayRendererJ2D</CODE> is not <CODE>Serializable</CODE> and
* should not be copied between JVMs.<P>
*/
public abstract class DisplayRendererJ2D
extends DisplayRenderer
implements RendererSourceListener
{
private VisADCanvasJ2D canvas;
/** root VisADGroup of scene graph under Locale */
private VisADGroup root = null;
/** single AffineTransform applied to all
* Data depictions */
private AffineTransform trans = null;
/** VisADGroup between root and all direct manipulation
* Data depictions */
private VisADGroup direct = null;
/** VisADGroup between root and all non-direct-manipulation
* Data depictions */
private VisADGroup non_direct = null;
/** MouseBehaviorJ2D */
private MouseBehaviorJ2D mouse = null;
/** box outline for data */
private VisADAppearance box = null;
/** cursor */
private VisADAppearance cursor = null;
/** AffineTransform between trans and cursor */
private AffineTransform cursor_trans = null;
/** single VisADSwitch between root and cursor */
private VisADSwitch cursor_switch = null;
/** children of cursor_switch */
private VisADGroup 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;
/** on / off state of axis scale */
private boolean scaleOn = false;
/** single VisADSwitch between root and box */
private VisADSwitch box_switch = null;
/** children of box_switch */
private VisADGroup box_on = null, box_off = null;
/** on / off state of box */
private boolean boxOn = false;
/** single VisADSwitch between root and scales */
private VisADSwitch scale_switch = null;
/** children of scale_switch */
private VisADGroup scale_on = null, scale_off = null;
/** 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;
public DisplayRendererJ2D () {
super();
}
/**
* 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
{
super.setDisplay(dpy);
dpy.addRendererSourceListener(this);
boxOn = getRendererControl().getBoxOn();
}
public VisADGroup getRoot() {
return root;
}
public void setClip(float xlow, float xhi, float ylow, float yhi) {
canvas.setClip(xlow, xhi, ylow, yhi);
}
public void unsetClip() {
canvas.unsetClip();
}
/**
* 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)
{
// initialize box colors
if (box != null) {
try {
ctl.setBoxColor(box.red, box.green, box.blue);
} catch (Throwable t) {
// ignore any initialization problems
}
}
// initialize cursor colors
if (cursor != null) {
try {
ctl.setBoxColor(cursor.red, cursor.green, cursor.blue);
} catch (Throwable t) {
// ignore any initialization problems
}
}
// initialize background colors
if (canvas != null) {
float[] ca = canvas.getBackgroundColor();
try {
ctl.setBackgroundColor(ca[0], ca[1], ca[2]);
} catch (Throwable t) {
// ignore any initialization problems
}
}
// update box visibility
try {
ctl.setBoxOn(boxOn);
} catch (Throwable t) {
// ignore any initialization problems
}
}
/**
* Utility routine which updates a <CODE>VisADAppearance</CODE> object
* to use the colors specified in the <CODE>float[3]</CODE> array.
* @param appear Currently used colors.
* @param colors New colors.
* @return <CODE>true</CODE> if any color was updated.
*/
private final boolean updateColors(VisADAppearance appear, float[] colors)
{
if (appear == null) {
return false;
}
boolean fixed = false;
for (int i = 0; i < 3; i++) {
float a;
switch (i) {
case 0: a = appear.red; break;
case 1: a = appear.green; break;
default:
case 2: a = appear.blue; break;
}
if (!Util.isApproximatelyEqual(a, colors[i])) {
switch (i) {
case 0: appear.red = colors[i]; break;
case 1: appear.green = colors[i]; break;
default:
case 2: appear.blue = colors[i]; break;
}
fixed = true;
}
}
return fixed;
}
/**
* 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)
throws VisADException, RemoteException
{
RendererControl ctl = (RendererControl )evt.getControl();
float[] color;
// update box colors
color = ctl.getBoxColor();
if (updateColors(box, color)) {
getCanvas().scratchImages();
}
// update cursor colors
color = ctl.getCursorColor();
if (updateColors(cursor, color)) {
render_trigger();
}
// update background colors
float[] ca = canvas.getBackgroundColor();
float[] ct = ctl.getBackgroundColor();
if (!Util.isApproximatelyEqual(ca[0], ct[0]) ||
!Util.isApproximatelyEqual(ca[1], ct[1]) ||
!Util.isApproximatelyEqual(ca[2], ct[2]))
{
canvas.setBackgroundColor(ct[0], ct[1], ct[2]);
canvas.scratchImages();
}
// update box visibility
boolean on = ctl.getBoxOn();
if (on != boxOn) {
boxOn = on;
box_switch.setWhichChild(boxOn ? 1 : 0);
canvas.scratchImages();
}
}
public AffineTransform getTrans() {
return trans;
}
public VisADCanvasJ2D getCanvas() {
return canvas;
}
public BufferedImage getImage() {
BufferedImage image = null;
while (image == null) {
try {
synchronized (this) {
canvas.captureFlag = true;
canvas.renderTrigger();
// System.out.println("getImage wait");
wait();
}
}
catch(InterruptedException e) {
// note notify generates a normal return from wait rather
// than an Exception - control doesn't normally come here
}
image = canvas.captureImage;
canvas.captureImage = null;
// System.out.println("getImage (image == null) = " + (image == null));
}
if (getDisplay().getComponent() == null) {
// offscreen
// this is a total hack; works for reasons not understood
for (int i=0; i<2; i++) {
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ImageIO.write(image, "image/jpeg", bout);
bout.flush();
bout.close();
}
catch (IOException e) {
}
}
// System.out.println("ByteArrayOutputStream done");
}
return image;
}
void notifyCapture() {
synchronized (this) {
notify();
}
}
public VisADGroup getCursorOnBranch() {
return cursor_on;
}
public VisADGroup getBoxOnBranch() {
return box_on;
}
public void setCursorOn(boolean on) {
cursorOn = on;
if (on) {
cursor_switch.setWhichChild(1); // set cursor on
setCursorStringVector();
}
else {
cursor_switch.setWhichChild(0); // set cursor off
setCursorStringVector(null);
}
render_trigger();
}
public void setDirectOn(boolean on) {
directOn = on;
if (!on) {
setCursorStringVector(null);
render_trigger();
}
}
public VisADGroup getDirect() {
return direct;
}
public VisADGroup getNonDirect() {
return non_direct;
}
/**
* Create scene graph root, if none exists, with Transform,
* direct manipulation root, and non-direct-manipulation root;
* create special graphics (e.g., 3-D box, SkewT background),
* any lights, any user interface embedded in scene.
* @param c
* @return Scene graph root.
* @exception DisplayException
*/
public abstract VisADGroup createSceneGraph(VisADCanvasJ2D c)
throws DisplayException;
/** @deprecated use createBasicSceneGraph(VisADCanvasJ2D c,
MouseBehaviorJ2D m, VisADAppearance bx, VisADAppearance cr)
instead */
public VisADGroup createBasicSceneGraph(VisADCanvasJ2D c,
MouseBehaviorJ2D m) throws DisplayException {
VisADAppearance box = new VisADAppearance();
VisADAppearance cursor = new VisADAppearance();
return createBasicSceneGraph(c, m, box, cursor);
}
/**
* Create scene graph root, if none exists, with Transform
* and direct manipulation root.
* @param c
* @param m
* @return Scene graph root.
* @exception DisplayException
*/
public VisADGroup createBasicSceneGraph(VisADCanvasJ2D c,
MouseBehaviorJ2D m, VisADAppearance bx, VisADAppearance cr)
throws DisplayException {
if (root != null) return root;
mouse = m;
canvas = c;
box = bx;
cursor = cr;
canvas.addMouseBehavior(mouse);
// Create the root of the branch graph
root = new VisADGroup();
// create the VisADGroup that is the parent of direct
// manipulation Data object VisADGroup objects
direct = new VisADGroup();
root.addChild(direct);
directOn = false;
// create the VisADGroup that is the parent of non-direct-
// manipulation Data object VisADGroup objects
non_direct = new VisADGroup();
root.addChild(non_direct);
canvas.setDirect(direct, non_direct);
cursor_trans = new AffineTransform();
cursor_switch = new VisADSwitch();
cursor_on = new VisADGroup();
cursor_off = new VisADGroup();
cursor_switch.addChild(cursor_off);
cursor_switch.addChild(cursor_on);
cursor_switch.setWhichChild(0); // initially off
cursorOn = false;
box_switch = new VisADSwitch();
box_on = new VisADGroup();
box_off = new VisADGroup();
box_switch.addChild(box_off);
box_switch.addChild(box_on);
box_switch.setWhichChild(1); // initially on
root.addChild(box_switch);
try {
setBoxOn(true);
} catch (Exception e) {
}
scale_switch = new VisADSwitch();
root.addChild(scale_switch);
scale_on = new VisADGroup();
scale_off = new VisADGroup();
scale_switch.addChild(scale_off);
scale_switch.addChild(scale_on);
scale_switch.setWhichChild(0); // initially off
scaleOn = false;
// set background color
float[] ctlBg = getRendererControl().getBackgroundColor();
canvas.setBackgroundColor(ctlBg[0], ctlBg[1], ctlBg[2]);
return root;
}
public MouseBehavior getMouseBehavior() {
return mouse;
}
public void addSceneGraphComponent(VisADGroup group)
throws DisplayException {
non_direct.addChild(group);
}
public void addDirectManipulationSceneGraphComponent(VisADGroup group,
DirectManipulationRendererJ2D renderer) throws DisplayException {
direct.addChild(group);
directs.addElement(renderer);
}
public void clearScene(DataRenderer renderer) {
directs.removeElement(renderer);
}
/**
* Returns the location of the last unmodified, middle mouse button press.
* @return The location of the last unmodified, middle
* mouse button press as (Display.XAxis,
* Display.YAxis, 0.0).
*/
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) {
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) {
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];
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() {
cursor_trans.setToTranslation((double) cursorX, (double) cursorY);
if (cursorOn) {
setCursorStringVector();
}
else {
render_trigger();
}
}
public void render_trigger() {
canvas.renderTrigger();
}
public boolean anyCursorStringVector() {
if (cursorOn) return true;
Enumeration renderers = ((Vector) directs.clone()).elements();
while (renderers.hasMoreElements()) {
DirectManipulationRendererJ2D r =
(DirectManipulationRendererJ2D) renderers.nextElement();
VisADGroup extra_branch = r.getExtraBranch();
if (extra_branch != null) return true;
}
if (cursorOn || directOn) {
if (!getCursorStringVector().isEmpty()) return true;
}
Vector rendererVector = getDisplay().getRendererVector();
renderers = rendererVector.elements();
while (renderers.hasMoreElements()) {
DataRenderer renderer = (DataRenderer) renderers.nextElement();
if (!renderer.getExceptionVector().isEmpty()) return true;
}
if (getWaitFlag() && getWaitMessageVisible()) return true;
return false;
}
/**
* Whenever <CODE>cursorOn</CODE> or <CODE>directOn</CODE> is
* <CODE>true</CODE>, display Strings in cursorStringVector.
* @param graphics
* @param tgeometry
* @param width
* @param height
*/
public void drawCursorStringVector(Graphics graphics,
AffineTransform tgeometry, int width, int height) {
// draw cursor
AffineTransform t = new AffineTransform(tgeometry);
if (cursorOn) {
t.concatenate(cursor_trans);
VisADAppearance appearance = (VisADAppearance) cursor_on.getChild(0);
if (appearance != null) {
VisADCanvasJ2D.drawAppearance(graphics, appearance, t, null);
}
t = new AffineTransform(tgeometry);
}
// draw direct manipulation extra_branch's
Enumeration renderers = ((Vector) directs.clone()).elements();
while (renderers.hasMoreElements()) {
DirectManipulationRendererJ2D r =
(DirectManipulationRendererJ2D) renderers.nextElement();
VisADGroup extra_branch = r.getExtraBranch();
if (extra_branch != null) {
Vector children = ((VisADGroup) extra_branch).getChildren();
Enumeration childs = children.elements();
while (childs.hasMoreElements()) {
VisADAppearance child =
(VisADAppearance) childs.nextElement();
VisADCanvasJ2D.drawAppearance(graphics, child, t, null);
}
}
}
// set cursor color
float[] c3;
try {
c3 = getCursorColor();
} catch (Exception e) {
System.err.println("Yikes! Couldn't get cursor color");
// default to white
c3 = new float[] {1.0f, 1.0f, 1.0f};
}
graphics.setColor(new Color(c3[0], c3[1], c3[2]));
// draw cursor strings in upper left corner of screen
graphics.setFont(new Font("Times New Roman", Font.PLAIN, 10));
int x = 1;
int y = 10;
if (cursorOn || directOn) {
Enumeration strings = getCursorStringVector().elements();
while(strings.hasMoreElements()) {
String string = (String) strings.nextElement();
graphics.drawString(string, x, y);
y += 12;
}
}
// draw Exception strings in lower left corner of screen
x = 1;
y = height - 2;
Vector rendererVector = getDisplay().getRendererVector();
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();
graphics.drawString(string, x, y);
y -= 12;
}
}
// draw wait flag in lower left corner of screen
if (getWaitFlag() && getWaitMessageVisible()) {
graphics.drawString("please wait . . .", x, y);
y -= 12;
}
}
public DataRenderer findDirect(VisADRay ray, int mouseModifiers) {
DirectManipulationRendererJ2D renderer = null;
float distance = Float.MAX_VALUE;
Enumeration renderers = ((Vector) directs.clone()).elements();
while (renderers.hasMoreElements()) {
DirectManipulationRendererJ2D r =
(DirectManipulationRendererJ2D) 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;
}
}
public boolean anyDirects() {
return !directs.isEmpty();
}
/**
* Allow scales to be displayed if they are set on.
* @param on true to turn them on, false to set them invisible
*/
public void setScaleOn(boolean on) {
boolean oldOn = scaleOn;
scaleOn = on;
if (on) {
scale_switch.setWhichChild(1); // on
}
else {
scale_switch.setWhichChild(0); // off
}
if (scaleOn != oldOn) {
canvas.scratchImages();
}
}
/**
* 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 {
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 {
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 {
// add array to scale_on
// replace any existing at axis, axis_ordinal
VisADAppearance appearance = new VisADAppearance();
appearance.red = scale_color[0];
appearance.green = scale_color[1];
appearance.blue = scale_color[2];
appearance.color_flag = true;
appearance.array = array;
VisADGroup group = new VisADGroup();
group.addChild(appearance);
if (labels != null)
{
VisADAppearance labelAppearance = new VisADAppearance();
labelAppearance.red = scale_color[0];
labelAppearance.green = scale_color[1];
labelAppearance.blue = scale_color[2];
labelAppearance.color_flag = true;
labelAppearance.array = labels;
group.addChild(labelAppearance);
}
// may only add VisADGroup 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++) {
VisADGroup empty = new VisADGroup();
scale_on.addChild(empty);
}
}
scale_on.setChild(group, m);
}
canvas.scratchImages(); // WLH 26 Jan 2001
}
/**
* Remove all the scales being rendered.
*/
public void clearScales() {
if (scale_on != null) {
synchronized (scale_on) {
int n = scale_on.numChildren();
for (int i=n-1; i>=0; i--) {
scale_on.removeChild(i);
}
}
}
}
/**
* Remove a particular scale being rendered.
* @param axisScale scale to be removed
*/
public void clearScale(AxisScale axisScale) {
int axis = axisScale.getAxis();
int axis_ordinal = axisScale.getAxisOrdinal();
int dim = getMode2D() ? 2 : 3;
try {
synchronized (scale_on) {
int n = scale_on.numChildren();
int m = dim * axis_ordinal + axis;
if (m >= n) {
for (int i=n; i<=m; i++) {
VisADGroup empty = new VisADGroup();
scale_on.addChild(empty);
}
}
VisADGroup empty = new VisADGroup();
scale_on.setChild(empty, m);
canvas.scratchImages();
}
} catch (VisADException ve) {;}
}
public void setTransform2D(AffineTransform t) {
trans = new AffineTransform(t);
}
/**
* 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) {
DisplayRealType type = map.getDisplayScalar();
DisplayImplJ2D display = (DisplayImplJ2D) 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 (ProjectionControlJ2D) 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(AnimationControlJ2D.class);
if (control != null) return control;
else return new AnimationControlJ2D(display, (RealType) map.getScalar());
}
else if (type.equals(Display.SelectValue)) {
return new ValueControlJ2D(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;
}
}
public DataRenderer makeDefaultRenderer() {
return new DefaultRendererJ2D();
}
public boolean legalDataRenderer(DataRenderer renderer) {
return (renderer instanceof RendererJ2D);
}
public void rendererDeleted(DataRenderer renderer)
{
clearScene(renderer);
}
public void setLineWidth(float width) {
}
/**
* Add a <CODE>KeyboardBehavior</CODE> for keyboard control of translation
* and zoom. This adds a <CODE>KeyListener</CODE> to the VisADCanvasJ2D to
* handle the behaviors for the arrow keys. Do not use this in conjunction
* with other <CODE>KeyListener</CODE>s that handle events for the arrow keys.
* @param behavior keyboard behavior to add
*/
public void addKeyboardBehavior(KeyboardBehaviorJ2D behavior)
{
getCanvas().addKeyboardBehavior(behavior);
}
public void setWaitFlag(boolean b) {
boolean old = getWaitFlag();
super.setWaitFlag(b);
if (b != old) {
if (canvas != null) canvas.renderTrigger();
}
}
public int getTextureWidthMax() {
return Integer.MAX_VALUE;
}
public int getTextureHeightMax() {
return Integer.MAX_VALUE;
}
}