//
// PointManipulationRendererJ3D.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.bom;
import java.awt.event.InputEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.rmi.RemoteException;
import java.util.Enumeration;
import java.util.Vector;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Group;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import visad.BadDirectManipulationException;
import visad.CellImpl;
import visad.CoordinateSystem;
import visad.DataDisplayLink;
import visad.DataReference;
import visad.DataReferenceImpl;
import visad.Display;
import visad.DisplayImpl;
import visad.DisplayRealType;
import visad.DisplayTupleType;
import visad.FlatField;
import visad.FunctionType;
import visad.Integer2DSet;
import visad.Real;
import visad.RealTuple;
import visad.RealTupleType;
import visad.RealType;
import visad.ScalarMap;
import visad.ScalarType;
import visad.Unit;
import visad.VisADException;
import visad.VisADRay;
import visad.java3d.DirectManipulationRendererJ3D;
import visad.java3d.DisplayImplJ3D;
/**
PointManipulationRendererJ3D is the VisAD class for direct
manipulation of single points
*/
public class PointManipulationRendererJ3D extends DirectManipulationRendererJ3D {
private RealType x = null;
private RealType y = null;
private RealTupleType xy = null;
private int mouseModifiersMask = 0;
private int mouseModifiersValue = 0;
private BranchGroup branch = null;
private BranchGroup group = null;
/** this DirectManipulationRenderer is quite different - it does not
render its data, but only place values into its DataReference
on right mouse button press;
it uses xarg and yarg to determine spatial ScalarMaps */
public PointManipulationRendererJ3D (RealType xarg, RealType yarg) {
// Don't match any modifier combinations (mmm = 0)
// Don't test for any - ie: accept (and steal) all combinations (mmv = 0)
this(xarg, yarg, 0, 0);
}
/**
* xarg and yarg determine spatial ScalarMaps; mmm and mmv determine whether
* SHIFT or CTRL keys are required - this is needed since this is a greedy
* DirectManipulationRenderer that will grab any right mouse click (that
* intersects its 2-D sub-manifold)
*
* @param mmm
* - "Mouse Modifier Mask", matches the modifiers we want plus
* all that we don't want
* @param mmv
* - "Mouse Modifier Value", equals the subset of mask that we
* want to match
*/
public PointManipulationRendererJ3D (RealType xarg, RealType yarg, int mmm, int mmv) {
super();
x = xarg;
y = yarg;
mouseModifiersMask = mmm;
mouseModifiersValue = mmv;
}
/** don't render - just return BranchGroup for scene graph to
render rectangle into */
public synchronized BranchGroup doTransform()
throws VisADException, RemoteException {
branch = new BranchGroup();
branch.setCapability(BranchGroup.ALLOW_DETACH);
branch.setCapability(Group.ALLOW_CHILDREN_READ);
branch.setCapability(Group.ALLOW_CHILDREN_WRITE);
branch.setCapability(Group.ALLOW_CHILDREN_EXTEND);
// check type and maps for valid direct manipulation
if (!getIsDirectManipulation()) {
throw new BadDirectManipulationException(getWhyNotDirect() +
": DirectManipulationRendererJ3D.doTransform");
}
setBranch(branch);
return branch;
}
/** for use in drag_direct */
private transient DataDisplayLink link = null;
private transient DataReference ref = null;
private transient ScalarMap xmap = null;
private transient ScalarMap ymap = null;
float[] default_values;
/** arrays of length one for inverseScaleValues */
private float[] f = new float[1];
private float[] d = new float[1];
/** information calculated by checkDirect */
/** explanation for invalid use of DirectManipulationRenderer */
private String whyNotDirect = null;
/** dimension of direct manipulation
(always 2 for PointManipulationRendererJ3D) */
private int directManifoldDimension = 2;
/** spatial DisplayTupleType other than
DisplaySpatialCartesianTuple */
private DisplayTupleType tuple;
private CoordinateSystem tuplecs;
private int xindex = -1;
private int yindex = -1;
private int otherindex = -1;
private float othervalue;
private float[][] first_x;
/** possible values for whyNotDirect */
private final static String xandyNotMatch =
"x and y spatial domains don't match";
private final static String xandyNotSpatial =
"x and y must be mapped to spatial";
public void checkDirect() throws VisADException, RemoteException {
setIsDirectManipulation(false);
DisplayImpl display = getDisplay();
DataDisplayLink[] Links = getLinks();
if (Links == null || Links.length == 0) {
link = null;
return;
}
link = Links[0];
ref = link.getDataReference();
default_values = link.getDefaultValues();
xmap = null;
ymap = null;
Vector scalar_map_vector = display.getMapVector();
Enumeration en = scalar_map_vector.elements();
while (en.hasMoreElements()) {
ScalarMap map = (ScalarMap) en.nextElement();
ScalarType real = map.getScalar();
if (real.equals(x)) {
DisplayRealType dreal = map.getDisplayScalar();
DisplayTupleType t = dreal.getTuple();
if (t != null &&
(t.equals(Display.DisplaySpatialCartesianTuple) ||
(t.getCoordinateSystem() != null &&
t.getCoordinateSystem().getReference().equals(
Display.DisplaySpatialCartesianTuple)))) {
xmap = map;
xindex = dreal.getTupleIndex();
if (tuple == null) {
tuple = t;
}
else if (!t.equals(tuple)) {
whyNotDirect = xandyNotMatch;
return;
}
}
}
if (real.equals(y)) {
DisplayRealType dreal = map.getDisplayScalar();
DisplayTupleType t = dreal.getTuple();
if (t != null &&
(t.equals(Display.DisplaySpatialCartesianTuple) ||
(t.getCoordinateSystem() != null &&
t.getCoordinateSystem().getReference().equals(
Display.DisplaySpatialCartesianTuple)))) {
ymap = map;
yindex = dreal.getTupleIndex();
if (tuple == null) {
tuple = t;
}
else if (!t.equals(tuple)) {
whyNotDirect = xandyNotMatch;
return;
}
}
}
}
if (xmap == null || ymap == null) {
whyNotDirect = xandyNotSpatial;
return;
}
xy = new RealTupleType(x, y);
// get default value for other component of tuple
otherindex = 3 - (xindex + yindex);
DisplayRealType dreal = (DisplayRealType) tuple.getComponent(otherindex);
int index = getDisplay().getDisplayScalarIndex(dreal);
othervalue = (index > 0) ? default_values[index] :
(float) dreal.getDefaultValue();
if (Display.DisplaySpatialCartesianTuple.equals(tuple)) {
tuple = null;
tuplecs = null;
}
else {
tuplecs = tuple.getCoordinateSystem();
}
directManifoldDimension = 2;
setIsDirectManipulation(true);
}
public String getWhyNotDirect() {
return whyNotDirect;
}
public void addPoint(float[] x) throws VisADException {
// may need to do this for performance
}
// methods customized from DataRenderer:
public CoordinateSystem getDisplayCoordinateSystem() {
return tuplecs;
}
/** set spatialValues from ShadowType.doTransform */
public synchronized void setSpatialValues(float[][] spatial_values) {
// do nothing
}
/** check if ray intersects sub-manifold
@return float, 0 - hit, Float.MAX_VALUE - no hit
*/
public synchronized float checkClose(double[] origin, double[] direction) {
int mouseModifiers = getLastMouseModifiers();
if ((mouseModifiers & mouseModifiersMask) != mouseModifiersValue) {
return Float.MAX_VALUE;
}
try {
float r = findRayManifoldIntersection(true, origin, direction, tuple,
otherindex, othervalue);
if (r == r) {
return 0.0f;
}
else {
return Float.MAX_VALUE;
}
}
catch (VisADException ex) {
return Float.MAX_VALUE;
}
}
public void stop_direct() {
}
public synchronized void drag_direct(VisADRay ray, boolean first,
int mouseModifiers) {
if (ref == null) return;
if (!first) return;
double[] origin = ray.position;
double[] direction = ray.vector;
try {
float r = findRayManifoldIntersection(true, origin, direction, tuple,
otherindex, othervalue);
if (r != r) {
if (group != null) group.detach();
return;
}
float[][] xx = {{(float) (origin[0] + r * direction[0])},
{(float) (origin[1] + r * direction[1])},
{(float) (origin[2] + r * direction[2])}};
if (tuple != null) xx = tuplecs.fromReference(xx);
first_x = xx;
Vector vect = new Vector();
f[0] = xx[xindex][0];
d = xmap.inverseScaleValues(f);
// WLH 31 Aug 2000
Real rr = new Real(x, d[0]);
Unit overrideUnit = xmap.getOverrideUnit();
Unit rtunit = x.getDefaultUnit();
// units not part of Time string
if (overrideUnit != null && !overrideUnit.equals(rtunit) &&
!RealType.Time.equals(x)) {
double dval = overrideUnit.toThis((double) d[0], rtunit);
rr = new Real(x, dval, overrideUnit);
}
String valueString = rr.toValueString();
vect.addElement(x.getName() + " = " + valueString);
f[0] = xx[yindex][0];
d = ymap.inverseScaleValues(f);
// WLH 31 Aug 2000
rr = new Real(y, d[0]);
overrideUnit = ymap.getOverrideUnit();
rtunit = y.getDefaultUnit();
// units not part of Time string
if (overrideUnit != null && !overrideUnit.equals(rtunit) &&
!RealType.Time.equals(y)) {
double dval = overrideUnit.toThis((double) d[0], rtunit);
rr = new Real(y, dval, overrideUnit);
}
valueString = rr.toValueString();
valueString = new Real(y, d[0]).toValueString();
vect.addElement(y.getName() + " = " + valueString);
// getDisplayRenderer().setCursorStringVector(vect);
double[] dd = new double[2];
f[0] = first_x[xindex][0];
d = xmap.inverseScaleValues(f);
dd[0] = d[0];
f[0] = first_x[yindex][0];
d = ymap.inverseScaleValues(f);
dd[1] = d[0];
RealTuple rt = new RealTuple(xy, dd);
ref.setData(rt);
} // end try
catch (VisADException e) {
// do nothing
System.out.println("drag_direct " + e);
e.printStackTrace();
}
catch (RemoteException e) {
// do nothing
System.out.println("drag_direct " + e);
e.printStackTrace();
}
}
public Object clone() {
return new PointManipulationRendererJ3D(x, y, mouseModifiersMask,
mouseModifiersValue);
}
private static final int N = 64;
/** test PointManipulationRendererJ3D */
public static void main(String args[])
throws VisADException, RemoteException {
RealType x = RealType.getRealType("x");
RealType y = RealType.getRealType("y");
RealTupleType xy = new RealTupleType(x, y);
RealType c = RealType.getRealType("c");
FunctionType ft = new FunctionType(xy, c);
// construct Java3D display and mappings
DisplayImpl display = new DisplayImplJ3D("display1");
if (args.length == 0 || args[0].equals("z")) {
display.addMap(new ScalarMap(x, Display.XAxis));
display.addMap(new ScalarMap(y, Display.YAxis));
}
else if (args[0].equals("x")) {
display.addMap(new ScalarMap(x, Display.YAxis));
display.addMap(new ScalarMap(y, Display.ZAxis));
}
else if (args[0].equals("y")) {
display.addMap(new ScalarMap(x, Display.XAxis));
display.addMap(new ScalarMap(y, Display.ZAxis));
}
else if (args[0].equals("radius")) {
display.addMap(new ScalarMap(x, Display.Longitude));
display.addMap(new ScalarMap(y, Display.Latitude));
}
else if (args[0].equals("lat")) {
display.addMap(new ScalarMap(x, Display.Longitude));
display.addMap(new ScalarMap(y, Display.Radius));
}
else if (args[0].equals("lon")) {
display.addMap(new ScalarMap(x, Display.Latitude));
display.addMap(new ScalarMap(y, Display.Radius));
}
else {
display.addMap(new ScalarMap(x, Display.Longitude));
display.addMap(new ScalarMap(y, Display.Latitude));
}
display.addMap(new ScalarMap(c, Display.RGB));
Integer2DSet fset = new Integer2DSet(xy, N, N);
FlatField field = new FlatField(ft, fset);
float[][] values = new float[1][N * N];
int k = 0;
for (int i=0; i<N; i++) {
for (int j=0; j<N; j++) {
values[0][k++] = (i - N / 2) * (j - N / 2);
}
}
field.setSamples(values);
DataReferenceImpl field_ref = new DataReferenceImpl("field");
field_ref.setData(field);
display.addReference(field_ref);
RealTuple dummy_rt = new RealTuple(xy, new double[] {Double.NaN, Double.NaN});
final DataReferenceImpl ref = new DataReferenceImpl("rt");
ref.setData(dummy_rt);
int m = (args.length > 1) ? InputEvent.CTRL_MASK : 0;
display.addReferences(new PointManipulationRendererJ3D(x, y, m, m), ref);
CellImpl cell = new CellImpl() {
public void doAction() throws VisADException, RemoteException {
RealTuple rt = (RealTuple) ref.getData();
double dx = ((Real) rt.getComponent(0)).getValue();
double dy = ((Real) rt.getComponent(1)).getValue();
if (dx == dx && dy == dy) {
System.out.println("point (" + dx + ", " + dy + ")");
}
}
};
cell.addReference(ref);
// create JFrame (i.e., a window) for display and slider
JFrame frame = new JFrame("test PointManipulationRendererJ3D");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
// create JPanel in JFrame
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setAlignmentY(JPanel.TOP_ALIGNMENT);
panel.setAlignmentX(JPanel.LEFT_ALIGNMENT);
frame.getContentPane().add(panel);
// add display to JPanel
panel.add(display.getComponent());
// set size of JFrame and make it visible
frame.setSize(500, 500);
frame.setVisible(true);
}
}