//
// GridEdit.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.util.*;
import visad.java3d.*;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Vector;
import java.util.Enumeration;
import java.rmi.*;

/**
GridEdit is the VisAD class for warping and modifying fields.

Construct a GridEdit object linked to a 2-D grid [a FlatField with MathType ((x, y) -> range)]) or a sequence of 2-D grids [a FieldImpl with MathType (t -> ((x, y) -> range))], and a DisplayImpl. The grid or grids must all have the same domain Set, which must be a Gridded2DSet or a GriddedSet with domain dimension = 2. The domain must be mapped to two spatial DisplayRealTypes. If a sequence of grids, the sequence domain must be mapped to Animation. The grid may have any number of range RealTypes. The GridEdit object operates in a sequence: 1. Invokes its start() method to start. 2. User drags grid warp motion lines with the right mouse button. These lines must lie inside the grid. 3. If user presses SHIFT while dragging a grid warp motion line, the program prompts for increments for values at the dragged location. 4. User can delete lines by clicking the right button on their end points, with CTRL pressed. 5. At any point after start(), the application can invoke stop() to stop the dragging process, and warp the grid. 6. After the grid has been warped, the application can invoke undo() to undo the paste and stop the process. 7. The process can be restarted by invoking start(), any number of times. The main() method illustrates a simple GUI and test case with a sequnece of grids. Run 'java visad.bom.GridEdit' to test with contour values, and run 'java visad.bom.GridEdit 1' to test with color values. */ public class GridEdit extends Object implements ActionListener { private boolean debug = false; private Field grids = null; private DisplayImpl display = null; private Object lock = new Object(); private RealType t = null; // non-null if animation private RealType x = null; private RealType y = null; private RealTupleType xy = null; private MathType range = null; // RealType or RealTupleType private int rangedim = 0; private int nts = 0; // number of steps in sequence Set tset = null; // t domain Set GriddedSet xyset = null; // (x, y) domain Set FunctionType grid_type; FlatField replacedff = null; FlatField savedff = null; AnimationControl acontrol = null; ScalarMap tmap = null; ScalarMap xmap = null; ScalarMap ymap = null; DisplayTupleType xtuple = null; DisplayTupleType ytuple = null; private CellImpl cell_rbl = null; private DataReferenceImpl ref_rbl = null; private RubberBandLineRendererJ3D rblr = null; private final static int NPICKS = 50; private int npicks = 0; private PickCell[] cell_picks = null; private DataReferenceImpl[] ref_picks = null; private PickManipulationRendererJ3D[] rend_picks = null; private float[][] delta_picks = null; private GridEdit thiscp = null; private int renderer_mask; private int dialog_mask; /**

     gs has MathType (t -> ((x, y) -> v)) or ((x, y) -> v)
     conditions on gs and display:
     1. x and y mapped to XAxis, YAxis, ZAxis
     2. (x, y) domain GriddedSet
     3. if (t -> ...), then t is mapped to Animation
*/ public GridEdit(Field gs, DisplayImplJ3D d) throws VisADException, RemoteException { grids = gs; display = d; renderer_mask = InputEvent.CTRL_MASK; dialog_mask = InputEvent.SHIFT_MASK; thiscp = this; FunctionType gstype = (FunctionType) gs.getType(); RealTupleType domain = gstype.getDomain(); int domdim = domain.getDimension(); if (domdim == 1) { t = (RealType) domain.getComponent(0); tset = gs.getDomainSet(); grid_type = (FunctionType) gstype.getRange(); xy = grid_type.getDomain(); int dim = xy.getDimension(); if (dim != 2) { throw new VisADException("bad grid Field domain dimension: " + dim); } range = grid_type.getRange(); nts = tset.getLength(); for (int i=0; i= nts) return; ff = (FlatField) grids.getSample(tindex); } else { ff = (FlatField) grids; } Data range = ff.getSample(indices[0]); if (range instanceof Real) { float value = (float) ((Real) range).getValue(); String name = ((RealType) range.getType()).getName(); String question = "increment " + name + " (current: " + value + ")"; String newvs = JOptionPane.showInputDialog(null, question); float newvalue = 0.0f; try { newvalue = Float.parseFloat(newvs); } catch (NumberFormatException e) { } delta_picks[0][index] = newvalue; // System.out.println(name + " increment = " + newvalue); } else if (range instanceof RealTuple) { for (int j=0; j= nts) return; ff = (FlatField) grids.getSample(index); } else { ff = (FlatField) grids; } savedff = new FlatField(grid_type, xyset); savedff.setSamples(ff.getFloats(false), false); float[][][] set_samples = new float[np][][]; float[][] deltas = new float[rangedim][np]; int k = 0; for (int i=0; i=0; i--) { indicesb[k++] = (ny - 1) * nx + i; } for (int i=ny-2; i>=1; i--) { indicesb[k++] = i * nx; } */ // just 4 corner points on border // int nb = 4; // int[] indicesb = {0, (ny - 1) * nx, ny * nx - 1, nx - 1}; // limit number of points on border int NB = 32; // int NB = 4; int nxb = (nx > NB) ? NB : nx; int nyb = (ny > NB) ? NB : ny; float xb = ((float) nx) / ((float) nxb); float yb = ((float) ny) / ((float) nyb); int nb = 2 * (nxb + nyb) - 4; // number of grid border points int[] indicesb = new int[nb]; int k = 0; for (int i=0; i (nx - 1)) ii = nx - 1; indicesb[k++] = ii; } for (int i=1; i<(nyb-1); i++) { int ii = Math.round(i * yb); if (ii < 1) ii = 1; if (ii > (ny - 2)) ii = ny - 2; indicesb[k++] = (ii + 1) * nx - 1; } for (int i=nxb-1; i>=0; i--) { int ii = Math.round(i * xb); if (ii < 0) ii = 0; if (ii > (nx - 1)) ii = nx - 1; indicesb[k++] = (ny - 1) * nx + ii; } for (int i=nyb-2; i>=1; i--) { int ii = Math.round(i * yb); if (ii < 1) ii = 1; if (ii > (ny - 2)) ii = ny - 2; indicesb[k++] = ii * nx; } float[][] samplesb = xyset.indexToValue(indicesb); // locations of grid border points // check if all move "to" points are inside 0.8 radius of circle float[][] set_locs = new float[2][np]; for (int i=0; i 0.64) { all_in = false; // System.out.println("not all_in d = " + d); break; } } if (all_in) { // all move "to" points inside 0.8 radius, so add circle boundary points int ne = 32; // weird bug for ne proportional to nx and ny int new_nb = nb + ne; float[][] new_samplesb = new float[2][new_nb]; System.arraycopy(samplesb[0], 0, new_samplesb[0], 0, nb); System.arraycopy(samplesb[1], 0, new_samplesb[1], 0, nb); float[][] circle_grid = new float[2][ne]; for (int i=0; i 0.0f) { tris[i][0] = a; tris[i][1] = b; tris[i][2] = c; } else { tris[i][0] = a; tris[i][1] = c; tris[i][2] = b; } // System.out.println("d " + tris[i][0] + " " + tris[i][1] + " " + tris[i][2]); } DelaunayCustom dc = new DelaunayCustom(moved, tris); Irregular2DSet iset = new Irregular2DSet(xy, moved, null, null, null, dc); // end of compute Irregular2DSet without any triangles whose vertices // are all 3 on the border */ // compute Irregular2DSet via simple Delaunay IrregularSet iset = new Irregular2DSet(xy, moved); // moveff is vector Field of motions, at Irregular2DSet combining // stationary border points with inverses of user drawn vectors FlatField moveff = new FlatField(move_type, iset); moveff.setSamples(mover); // interpolate inverse motions to grid locations FlatField move_interp = (FlatField) moveff.resample(xyset); // form a new "warped" Gridded2DSet of the locations // that grid move to under interpolate inverse motions float[][] bases = xyset.getSamples(true); // copy float[][] offsets = move_interp.getFloats(false); for (int i=0; i 0) { cmap = new ScalarMap(windy, Display.RGB); } else { cmap = new ScalarMap(windy, Display.IsoContour); } display1.addMap(cmap); ScalarMap amap = new ScalarMap(time, Display.Animation); display1.addMap(amap); AnimationControl acontrol = (AnimationControl) amap.getControl(); acontrol.setStep(500); // create an array of NX by NY winds FieldImpl field = new FieldImpl(seq_type, time_set); double[][] values = new double[6][NX * NY]; for (int k=0; k 0) { LabeledColorWidget lcw = new LabeledColorWidget(cmap); lcw.setMaximumSize(new Dimension(400, 200)); panel2.add(lcw); } else { ContourWidget cw = new ContourWidget(cmap); cw.setMaximumSize(new Dimension(400, 200)); panel2.add(cw); } panel2.add(new JLabel(" ")); panel2.add(panel3); panel2.setMaximumSize(new Dimension(400, 600)); panel.add(panel1); panel.add(panel2); frame.getContentPane().add(panel); // set size of JFrame and make it visible frame.setSize(800, 600); frame.setVisible(true); } public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); if (cmd.equals("start")) { try { start(); } catch (VisADException ex) { ex.printStackTrace(); } catch (RemoteException ex) { ex.printStackTrace(); } } else if (cmd.equals("stop")) { try { stop(); } catch (VisADException ex) { ex.printStackTrace(); } catch (RemoteException ex) { ex.printStackTrace(); } } else if (cmd.equals("undo")) { try { undo(); } catch (VisADException ex) { ex.printStackTrace(); } catch (RemoteException ex) { ex.printStackTrace(); } } } } /** * CellImpl for user clicks to delete move vectors * via setData(null) */ class PickCell extends CellImpl { private boolean skip; private DataRenderer rend; private DataReferenceImpl ref; public PickCell(DataReferenceImpl rf, DataRenderer rd) { rend = rd; ref = rf; skip = true; } public void doAction() throws VisADException, RemoteException { if (skip) { skip = false; } else { rend.toggle(false); skip = true; ref.setData(null); } } public void setSkip() { skip = true; } }

Ads help maintain this website.