// // PickManipulationRendererJ3D.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 visad.*; import visad.java3d.*; import java.awt.event.*; import javax.swing.*; import java.rmi.RemoteException; /** * PickManipulationRendererJ3D is the VisAD class for picking * data in 3D. */ public class PickManipulationRendererJ3D extends DirectManipulationRendererJ3D { private int mouseModifiersMask = 0; private int mouseModifiersValue = 0; /** * Default constructor */ public PickManipulationRendererJ3D () { this (0, 0); } /** * Construct a new PickManipulationRenderer using the mouseModifiers * supplied. mmm and mmv determine whehter 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 modifiers mask. * @param mmv mouse modifiers value. */ public PickManipulationRendererJ3D (int mmm, int mmv) { super(); mouseModifiersMask = mmm; mouseModifiersValue = mmv; } /** for use in drag_direct */ private transient DataDisplayLink link = null; private transient DataReference ref = null; private float[][] spatialValues = null; /** index into spatialValues found by checkClose */ private int closeIndex = -1; private int directManifoldDimension = -1; /** information calculated by checkDirect */ /** explanation for invalid use of DirectManipulationRenderer */ private String whyNotDirect = null; /** possible values for whyNotDirect */ private final static String notSimpleField = "not simple field"; private final static String notSimpleTuple = "not simple tuple"; private boolean stop = false; /** * Check if direct manipulation is possible. */ 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(); ShadowType shadow = link.getShadow().getAdaptedShadowType(); MathType type = link.getType(); if (type instanceof FunctionType) { if (shadow.getLevelOfDifficulty() != ShadowType.SIMPLE_FIELD) { whyNotDirect = notSimpleField; return; } } else if (type instanceof SetType) { if (shadow.getLevelOfDifficulty() != ShadowType.SIMPLE_FIELD) { whyNotDirect = notSimpleField; return; } } else { if (shadow.getLevelOfDifficulty() != ShadowType.SIMPLE_TUPLE) { whyNotDirect = notSimpleTuple; return; } } setIsDirectManipulation(true); } private int getDirectManifoldDimension() { return directManifoldDimension; } /** * If direct manipulation is not possible, get the error message * explaining why. * @return error message. Will be null if no errors. */ public String getWhyNotDirect() { return whyNotDirect; } /** * Add a point. a no-op at this point. * @param x point value. */ public void addPoint(float[] x) throws VisADException { // may need to do this for performance } // methods customized from DataRenderer: /** * Get the CoordinateSystem for the display side. * @return null for this DataRenderer */ public CoordinateSystem getDisplayCoordinateSystem() { return null; } /** * Set spatialValues from ShadowType.doTransform * @param spatial_values X, Y, Z values */ public synchronized void setSpatialValues(float[][] spatial_values) { // these are X, Y, Z values spatialValues = spatial_values; } /** * Check if ray intersects sub-manifold. * @param origin x,y,z values of the ray * @param direction x,y,z values of the ray? * @return distance from the spatial values. */ public synchronized float checkClose(double[] origin, double[] direction) { int mouseModifiers = getLastMouseModifiers(); if ((mouseModifiers & mouseModifiersMask) != mouseModifiersValue) { return Float.MAX_VALUE; } float distance = Float.MAX_VALUE; if (spatialValues == null) return distance; float o_x = (float) origin[0]; float o_y = (float) origin[1]; float o_z = (float) origin[2]; float d_x = (float) direction[0]; float d_y = (float) direction[1]; float d_z = (float) direction[2]; /* System.out.println("origin = " + o_x + " " + o_y + " " + o_z); System.out.println("direction = " + d_x + " " + d_y + " " + d_z); */ for (int i=0; i<spatialValues[0].length; i++) { float x = spatialValues[0][i] - o_x; float y = spatialValues[1][i] - o_y; float z = spatialValues[2][i] - o_z; float dot = x * d_x + y * d_y + z * d_z; x = x - dot * d_x; y = y - dot * d_y; z = z - dot * d_z; float d = (float) Math.sqrt(x * x + y * y + z * z); if (d < distance) { distance = d; closeIndex = i; } /* System.out.println("spatialValues["+i+"] = " + spatialValues[0][i] + " " + spatialValues[1][i] + " " + spatialValues[2][i] + " d = " + d); */ } /* System.out.println("checkClose: distance = " + distance); */ return distance; } /** * Return the index of the closes point. * @return index of closest point */ public int getCloseIndex() { return closeIndex; } /** * Actual workhorse method of manipulation renderer. It's what * gets called when the click is done. * @param ray ray of point where click is. * @param first if this is the first time. * @param mouseModifiers modifiers used with the mouse. */ public synchronized void drag_direct(VisADRay ray, boolean first, int mouseModifiers) { if (ref == null) return; if (first) { try { ref.setData(ref.getData()); } catch (VisADException e) { } catch (RemoteException e) { } } } public Object clone() { return new PickManipulationRendererJ3D(mouseModifiersMask, mouseModifiersValue); } /** test PickManipulationRendererJ3D */ public static void main(String args[]) throws VisADException, RemoteException { RealType x = RealType.getRealType("x"); RealType y = RealType.getRealType("y"); RealType z = RealType.getRealType("z"); FunctionType f1d = new FunctionType(x, y); RealTupleType xy = new RealTupleType(x, y); FunctionType f2d = new FunctionType(xy, z); TextType t = new TextType("text"); RealType s = RealType.getRealType("shape"); Data[] td = {new Real(x, 0.5), new Real(y, 0.5), new Real(z, 0.5), new Text(t, "text")}; Tuple text = new Tuple(td); Real[] sd = {new Real(x, -0.5), new Real(y, -0.5), new Real(z, -0.5), new Real(s, 0.0)}; RealTuple shape = new RealTuple(sd); Real real = new Real(x, -0.5); Real[] rtd = {new Real(x, 0.5), new Real(y, -0.5), new Real(z, 0.0)}; RealTuple real_tuple = new RealTuple(rtd); FlatField field1d = new FlatField(f1d, new Linear1DSet(x, -1.0, -0.5, 64)); double[][] values = new double[1][64]; for (int i=0; i<64; i++) values[0][i] = 0.5 + Math.abs(i - 31.5) / 63.0; field1d.setSamples(values); Set set2d = new Linear2DSet(xy, 0.5, 1.0, 32, -0.25, 0.25, 32); FlatField field2d = new FlatField(f2d, set2d); values = new double[1][1024]; int k = 0; for (int i=0; i<32; i++) { for (int j=0; j<32; j++) { values[0][k++] = Math.sqrt((i-15.5) * (i-15.5) + (j-15.5) * (j-15.5)) / 32.0; } } field2d.setSamples(values); // construct Java3D display and mappings DisplayImpl display = new DisplayImplJ3D("display"); DisplayRenderer dr = display.getDisplayRenderer(); dr.setPickThreshhold(0.2f); // allow sloppy picking ScalarMap xmap = new ScalarMap(x, Display.XAxis); display.addMap(xmap); xmap.setRange(-1.0, 1.0); ScalarMap ymap = new ScalarMap(y, Display.YAxis); display.addMap(ymap); ymap.setRange(-1.0, 1.0); ScalarMap zmap = new ScalarMap(z, Display.ZAxis); display.addMap(zmap); zmap.setRange(-1.0, 1.0); ScalarMap tmap = new ScalarMap(t, Display.Text); display.addMap(tmap); TextControl tcontrol = (TextControl) tmap.getControl(); tcontrol.setCenter(true); ScalarMap smap = new ScalarMap(s, Display.Shape); display.addMap(smap); ShapeControl scontrol = (ShapeControl) smap.getControl(); scontrol.setShapeSet(new Integer1DSet(s, 1)); VisADLineArray cross = new VisADLineArray(); cross.coordinates = new float[] {0.1f, 0.1f, 0.0f, -0.1f, -0.1f, 0.0f, 0.1f, -0.1f, 0.0f, -0.1f, 0.1f, 0.0f}; cross.vertexCount = cross.coordinates.length / 3; scontrol.setShapes(new VisADGeometryArray[] {cross}); GraphicsModeControl mode = display.getGraphicsModeControl(); mode.setScaleEnable(true); DataReferenceImpl tref = new DataReferenceImpl("text"); tref.setData(text); display.addReferences(new PickManipulationRendererJ3D(), tref); CellImpl cellt = new CellImpl() { private boolean first = true; public void doAction() throws VisADException, RemoteException { if (first) first = false; else System.out.println("text picked"); } }; cellt.addReference(tref); DataReferenceImpl sref = new DataReferenceImpl("shape"); sref.setData(shape); display.addReferences(new PickManipulationRendererJ3D(), sref); CellImpl cells = new CellImpl() { private boolean first = true; public void doAction() throws VisADException, RemoteException { if (first) first = false; else System.out.println("shape picked"); } }; cells.addReference(sref); DataReferenceImpl rref = new DataReferenceImpl("Real"); rref.setData(real); ConstantMap[] rmaps = {new ConstantMap(5.0, Display.PointSize)}; display.addReferences(new PickManipulationRendererJ3D(), rref, rmaps); CellImpl cellr = new CellImpl() { private boolean first = true; public void doAction() throws VisADException, RemoteException { if (first) first = false; else System.out.println("Real picked"); } }; cellr.addReference(rref); DataReferenceImpl rtref = new DataReferenceImpl("RealTuple"); rtref.setData(real_tuple); ConstantMap[] rtmaps = {new ConstantMap(5.0, Display.PointSize)}; display.addReferences(new PickManipulationRendererJ3D(), rtref, rtmaps); CellImpl cellrt = new CellImpl() { private boolean first = true; public void doAction() throws VisADException, RemoteException { if (first) first = false; else System.out.println("RealTuple picked"); } }; cellrt.addReference(rtref); DataReferenceImpl field1dref = new DataReferenceImpl("field1d"); field1dref.setData(field1d); final PickManipulationRendererJ3D pmr1d = new PickManipulationRendererJ3D(); display.addReferences(pmr1d, field1dref); CellImpl cellfield1d = new CellImpl() { private boolean first = true; public void doAction() throws VisADException, RemoteException { if (first) first = false; else { int i = pmr1d.getCloseIndex(); System.out.println("1-D Field picked, index = " + i); } } }; cellfield1d.addReference(field1dref); DataReferenceImpl field2dref = new DataReferenceImpl("field2d"); field2dref.setData(field2d); final PickManipulationRendererJ3D pmr2d = new PickManipulationRendererJ3D(); display.addReferences(pmr2d, field2dref); CellImpl cellfield2d = new CellImpl() { private boolean first = true; public void doAction() throws VisADException, RemoteException { if (first) first = false; else { int i = pmr2d.getCloseIndex(); System.out.println("2-D Field picked, index = " + i); } } }; cellfield2d.addReference(field2dref); DataReferenceImpl setref = new DataReferenceImpl("set"); setref.setData(set2d); ConstantMap[] smaps = {new ConstantMap(-1.0, Display.ZAxis)}; final PickManipulationRendererJ3D pmrset = new PickManipulationRendererJ3D(); display.addReferences(pmrset, setref, smaps); CellImpl cellset = new CellImpl() { private boolean first = true; public void doAction() throws VisADException, RemoteException { if (first) first = false; else { int i = pmrset.getCloseIndex(); System.out.println("set picked, index = " + i); } } }; cellset.addReference(setref); // create JFrame (i.e., a window) for display and slider JFrame frame = new JFrame("test PickManipulationRendererJ3D"); 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); } }