/* 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 */ import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.rmi.RemoteException; import java.util.Iterator; import java.util.Vector; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import visad.*; import visad.java2d.DisplayImplJ2D; import visad.java3d.DisplayImplJ3D; import visad.util.AnimationWidget; import visad.util.ClientServer; import visad.util.ContourWidget; import visad.util.GMCWidget; import visad.util.LabeledColorWidget; import visad.util.ProjWidget; import visad.util.RangeWidget; import visad.util.SelectRangeWidget; public class DisplaySwitch extends Thread { private DisplayImpl display = null; private DataReferenceImpl[] dpyRefs = null; private Data alphaData0 = null; private Data betaData0 = null; private Data betaData1 = null; private ConstantMap[] betaConstMaps = null; private JPanel dpyPanel = null; private JButton switchDim = null; private JButton switchData = null; private boolean startServer = false; private String hostName = null; private static final int maximumWaitTime = 60; private boolean dpy3D = false; private boolean dpyBeta = false; public DisplaySwitch(String[] args) throws RemoteException, VisADException { if (!processArgs(args)) { System.err.println("Exiting..."); System.exit(1); } startThreads(); } public boolean processArgs(String[] args) { boolean usage = false; String className = getClass().getName(); int pt = className.lastIndexOf('.'); final int ds = className.lastIndexOf('$'); if (ds > pt) { pt = ds; } String progName = className.substring(pt == -1 ? 0 : pt + 1); for (int i = 0; args != null && i < args.length; i++) { if (args[i].length() > 0 && args[i].charAt(0) == '-') { char ch = args[i].charAt(1); String str, result; switch (ch) { case 'c': str = (args[i].length() > 2 ? args[i].substring(2) : ((i + 1) < args.length ? args[++i] : null)); if (str == null) { System.err.println(progName + ": Missing hostname for \"-c\""); usage = true; } else if (startServer) { System.err.println(progName + ": Cannot specify both '-c' and '-s'!"); usage = true; } else { hostName = str; } break; case 's': if (hostName != null) { System.err.println(progName + ": Cannot specify both '-c' and '-s'!"); usage = true; } else { startServer = true; } break; default: System.err.println(progName + ": Unknown option \"-" + ch + "\""); usage = true; break; } } else { System.err.println(progName + ": Unknown keyword \"" + args[i] + "\""); usage = true; } } if (usage) { System.err.println("Usage: " + getClass().getName() + " [-c(lient) hostname] [-s(erver)]"); } return !usage; } boolean isServer() { return (startServer && hostName == null); } boolean isClient() { return (!startServer && hostName != null); } boolean isStandalone() { return (!startServer && hostName == null); } String getClientServerTitle() { if (isServer()) { return " server"; } else if (isClient()) { return " client"; } else if (isStandalone()) { return " standalone"; } return " unknown"; } LocalDisplay setupClientData() throws RemoteException, VisADException { RemoteServer client; try { client = ClientServer.connectToServer(hostName, getClass().getName(), true); } catch (VisADException ve) { System.err.println(ve.getMessage()); System.exit(1); client = null; } LocalDisplay[] dpys = ClientServer.getClientDisplays(client); if (dpys == null) { throw new VisADException("No remote displays found!"); } if (dpys.length != 1) { throw new VisADException("Multiple remote displays found!"); } return dpys[0]; } public void startThreads() throws RemoteException, VisADException { LocalDisplay local; if (isClient()) { local = setupClientData(); } else { DisplayImpl dpy = setupServerDisplay(); RemoteServerImpl server; if (!startServer) { server = null; } else { server = ClientServer.startServer(getClass().getName()); // add display to server if (dpy != null) { server.addDisplay(new RemoteDisplayImpl(dpy)); } } local = dpy; setupServerData(local); } setupUI(local); } ////////////////////////////////////////////////////////////////////////////// DisplayImpl setupServerDisplay() throws RemoteException, VisADException { display = new DisplayImplJ2D("display"); return display; } private static ScalarMap findMap(LocalDisplay dpy, RealType displayScalar) { if (displayScalar == null) { return null; } Iterator maps; try { maps = dpy.getMapVector().iterator(); } catch (Exception e) { maps = null; } if (maps != null) { while (maps.hasNext()) { ScalarMap smap = (ScalarMap )maps.next(); if (displayScalar.equals(smap.getDisplayScalar())) { return smap; } } } try { maps = dpy.getConstantMapVector().iterator(); } catch (Exception e) { maps = null; } if (maps != null) { while (maps.hasNext()) { ConstantMap cmap = (ConstantMap )maps.next(); if (displayScalar.equals(cmap.getDisplayScalar())) { return cmap; } } } return null; } private void buildMaps(LocalDisplay dpy) throws RemoteException, VisADException { RealType dom0 = RealType.getRealType("dom0"); RealType dom1 = RealType.getRealType("dom1"); dpy.addMap(new ScalarMap(RealType.Latitude, Display.XAxis)); dpy.addMap(new ScalarMap(RealType.Longitude, Display.YAxis)); dpy.addMap(new ScalarMap(dom1, Display.Green)); dpy.addMap(new ConstantMap(0.5, Display.Blue)); dpy.addMap(new ConstantMap(0.5, Display.Red)); dpy.addMap(new ScalarMap(dom0, Display.IsoContour)); dpy.addMap(new ScalarMap(dom1, Display.SelectRange)); dpy.addMap(new ScalarMap(dom1, Display.RGBA)); dpy.addMap(new ScalarMap(RealType.Time, Display.Animation)); } private DataImpl buildAlphaRefZero() throws RemoteException, VisADException { RealType dom0 = RealType.getRealType("dom0"); RealType dom1 = RealType.getRealType("dom1"); RealType[] types = {RealType.Latitude, RealType.Longitude}; RealTupleType earthLocation = new RealTupleType(types); RealType[] viTypes = {dom0, dom1}; RealTupleType viTT = new RealTupleType(viTypes); FunctionType viFunc = new FunctionType(earthLocation, viTT); RealType[] ivTypes = {dom1, dom0}; RealTupleType ivTT = new RealTupleType(ivTypes); FunctionType ivFunc = new FunctionType(earthLocation, ivTT); RealType[] time = {RealType.Time}; RealTupleType timeType = new RealTupleType(time); FunctionType timeVI = new FunctionType(timeType, viFunc); FunctionType timeIV = new FunctionType(timeType, ivFunc); int size = 64; int ntimes = 4; // 2 May 99, 15:51:00 double start = new DateTime(1999, 122, 57060).getValue(); Set timeSet = new Linear1DSet(timeType, start, start + 3000.0, ntimes); double[][] times = {{start, start + 600.0, start + 1200.0, start + 1800.0, start + 2400.0, start + 3000.0}}; Set timeGrid = new Gridded1DDoubleSet(timeType, times, times[0].length); FieldImpl setSequence = new FieldImpl(timeVI, timeSet); FieldImpl gridSequence = new FieldImpl(timeIV, timeGrid); FlatField flatVI = FlatField.makeField(viFunc, size, false); FlatField flatIV = FlatField.makeField(ivFunc, size, false); Real[] reals = {new Real(dom0, (float) size / 4.0f), new Real(dom1, (float) size / 8.0f)}; RealTuple val = new RealTuple(reals); for (int i=0; i<ntimes; i++) { setSequence.setSample(i, flatVI); flatVI = (FlatField) flatVI.add(val); } for (int i=0; i<times[0].length; i++) { gridSequence.setSample(i, flatIV); flatIV = (FlatField) flatIV.add(val); } FieldImpl[] images = {setSequence, gridSequence}; return new Tuple(images); } void setupAlphaRefs(LocalDisplay dpy) throws RemoteException, VisADException { if (alphaData0 == null) { alphaData0 = buildAlphaRefZero(); } dpyRefs = new DataReferenceImpl[1]; dpyRefs[0] = new DataReferenceImpl("dpyRef0"); dpyRefs[0].setData(alphaData0); dpy.addReference(dpyRefs[0], null); } private DataImpl buildBetaRefZero() throws RemoteException, VisADException { RealType dom0 = RealType.getRealType("dom0"); RealType dom1 = RealType.getRealType("dom1"); int isize = 16; RealTupleType revLocation; revLocation = new RealTupleType(RealType.Longitude, RealType.Latitude); RealTupleType domTypes = new RealTupleType(dom0, dom1); FunctionType func = new FunctionType(revLocation, domTypes); FlatField flat = FlatField.makeField(func, isize, false); double[][] vals = new double[2][isize * isize]; for (int i=0; i<isize; i++) { for (int j=0; j<isize; j++) { vals[0][j + isize * i] = (i + 1) * (j + 1); vals[1][j + isize * i] = ((double )i * 1.2) * ((double )j / 1.2); } } return flat; } private DataImpl buildBetaRefOne() throws RemoteException, VisADException { RealType dom0 = RealType.getRealType("dom0"); RealType dom1 = RealType.getRealType("dom1"); int isize = 16; RealTupleType earthLocation; earthLocation = new RealTupleType(RealType.Latitude, RealType.Longitude); RealTupleType domTypes = new RealTupleType(dom0, dom1); FunctionType func = new FunctionType(earthLocation, domTypes); FlatField flat = FlatField.makeField(func, isize, false); double[][] vals = new double[2][isize * isize]; for (int i=0; i<isize; i++) { for (int j=0; j<isize; j++) { vals[0][j + isize * i] = (i + 1) * (j + 1); vals[1][j + isize * i] = ((double )i * 1.2) * ((double )j / 1.2); } } flat.setSamples(vals, false); return flat; } void setupBetaRefs(LocalDisplay dpy) throws RemoteException, VisADException { if (betaData0 == null) { betaData0 = buildBetaRefZero(); } if (betaData1 == null) { betaData1 = buildBetaRefOne(); } if (betaConstMaps == null) { betaConstMaps = new ConstantMap[3]; betaConstMaps[0] = new ConstantMap(1.0, Display.Blue); betaConstMaps[1] = new ConstantMap(1.0, Display.Red); betaConstMaps[2] = new ConstantMap(0.0, Display.Green); } dpyRefs = new DataReferenceImpl[2]; dpyRefs[0] = new DataReferenceImpl("dpyRef0"); dpyRefs[0].setData(betaData0); dpy.addReference(dpyRefs[0], null); dpyRefs[1] = new DataReferenceImpl("dpyRef1"); dpyRefs[1].setData(betaData1); dpy.addReference(dpyRefs[1], betaConstMaps); } void setupServerData(LocalDisplay dpy) throws RemoteException, VisADException { buildMaps(dpy); setupAlphaRefs(dpy); } void switchDisplay(boolean rerollData) { // make sure we know which display we're switching if (display == null) { System.err.println("No display found!"); return; } // grab some info from the current display String name = display.getName(); int api; try { api = display.getAPI(); } catch (VisADException ve) { api = 0; } // try to create a new display in a different dimension DisplayImpl newDpy; try { if (dpy3D) { newDpy = new DisplayImplJ3D(name, api); } else { newDpy = new DisplayImplJ2D(name, api); } } catch (Exception e) { System.err.println("Couldn't create new display!"); return; } // save the old maps Vector sMaps = display.getMapVector(); Vector cMaps = display.getConstantMapVector(); // destroy the old display try { dpyPanel.remove(display.getComponent()); display.removeAllReferences(); display.clearMaps(); display = null; } catch (Exception e) { System.err.println("Ignoring " + e.getClass().getName() + ": " + e.getMessage()); // ignore any errors due to clearing out the old display } // add maps to new display if (sMaps != null) { int len = sMaps.size(); for (int i = 0; i < len; i++) { ScalarMap map = (ScalarMap )sMaps.elementAt(i); try { newDpy.addMap(map); } catch (Exception e) { System.err.println("Couldn't re-add ScalarMap " + map + ": " + e.getClass().getName() + ": " + e.getMessage()); e.printStackTrace(); } } } if (cMaps != null) { int len = cMaps.size(); for (int i = 0; i < len; i++) { ConstantMap map = (ConstantMap )cMaps.elementAt(i); try { newDpy.addMap(map); } catch (Exception e) { System.err.println("Couldn't re-add ConstantMap " + map + ": " + e.getClass().getName() + ": " + e.getMessage()); e.printStackTrace(); } } } if (dpyRefs == null || rerollData) { if (dpyBeta) { try { setupBetaRefs(newDpy); } catch (Exception e) { System.err.println("Couldn't re-init beta refs: " + e.getClass().getName() + ": " + e.getMessage()); e.printStackTrace(); } } else { try { setupAlphaRefs(newDpy); } catch (Exception e) { System.err.println("Couldn't re-init alpha refs: " + e.getClass().getName() + ": " + e.getMessage()); e.printStackTrace(); } } } else { for (int i = 0; i < dpyRefs.length; i++) { try { newDpy.addReference(dpyRefs[i], null); } catch (Exception e) { System.err.println("Couldn't re-add " + dpyRefs[i] + ": " + e.getClass().getName() + ": " + e.getMessage()); e.printStackTrace(); } } } display = newDpy; dpyPanel.add(display.getComponent()); } private Component buildSwitchButtons() { JPanel buttons = new JPanel(); buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS)); switchDim = new JButton("Change to 3D"); switchDim.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dpy3D = !dpy3D; switchDisplay(false); if (dpy3D) { switchDim.setText("Change to 2D"); } else { switchDim.setText("Change to 3D"); } } }); buttons.add(switchDim); switchData = new JButton("Change Data"); switchData.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { dpyBeta = !dpyBeta; switchDisplay(true); } }); buttons.add(switchData); return buttons; } Component getSpecialComponent(LocalDisplay dpy) throws RemoteException, VisADException { Vector v = dpy.getMapVector(); ScalarMap rgbaMap = findMap(dpy, Display.RGBA); JPanel widgets = new JPanel(); widgets.setLayout(new BoxLayout(widgets, BoxLayout.Y_AXIS)); dpyPanel = new JPanel(); dpyPanel.add(dpy.getComponent()); widgets.add(dpyPanel); widgets.add(new AnimationWidget(findMap(dpy, Display.Animation), 500)); widgets.add(new ContourWidget(findMap(dpy, Display.IsoContour))); widgets.add(new GMCWidget(dpy.getGraphicsModeControl())); widgets.add(new LabeledColorWidget(rgbaMap)); widgets.add(new ProjWidget(dpy.getProjectionControl())); widgets.add(new RangeWidget(rgbaMap)); widgets.add(new SelectRangeWidget(findMap(dpy, Display.SelectRange))); if (isServer() || isStandalone()) { widgets.add(buildSwitchButtons()); } return widgets; } void setupUI(LocalDisplay dpy) throws RemoteException, VisADException { Component special = getSpecialComponent(dpy); Container content; if (special instanceof Container) { content = (Container )special; } else { JPanel wrapper = new JPanel(); wrapper.setLayout(new BorderLayout()); wrapper.add("Center", special); content = wrapper; } JFrame jframe = new JFrame(getFrameTitle() + getClientServerTitle()); jframe.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) {System.exit(0);} }); jframe.setContentPane(content); jframe.pack(); jframe.setVisible(true); } String getFrameTitle() { return "2d/3d display switch"; } public String toString() { return ": Changing between 2d and 3d display"; } public static void main(String[] args) throws RemoteException, VisADException { new DisplaySwitch(args); } }