/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package visad;
import visad.util.CubicInterpolator;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import visad.data.text.TextAdapter;
/**
*
* @author rink
*/
public class TrajectoryManager {
static float[][] circle;
private int coordCnt = 0;
private int colorCnt = 0;
private int vertCnt = 0;
private int totNpairs = 0;
private int dataDomainLength;
private float[] coordinates = null;
private byte[] colors = null;
private int clrDim = 3;
private int numSpatialPts;
private boolean[] markGrid;
private int[] markGridTime;
private int cnt=0;
public static boolean doStartOffset = false;
public static int[] o_j = new int[] {0, 0, 1, 1};
public static int[] o_i = new int[] {0, 1, 0, 1};
float[][] startPts;
byte[][] startClrs;
public static final int LINE = TrajectoryParams.LINE;
public static final int RIBBON = TrajectoryParams.RIBBON;
public static final int CYLINDER = TrajectoryParams.CYLINDER;
public static final int DEFORM_RIBBON = TrajectoryParams.DEFORM_RIBBON;
public static final int POINT = TrajectoryParams.POINT;
public static final String PPOP_TRAJECTORY_START_POINTS_FILE = "visad.trajectory.startPointsFile";
double trajVisibilityTimeWindow;
double trajRefreshInterval;
double trajLifetime;
boolean manualIntrpPts;
boolean trajDoIntrp = true;
boolean trajCachingEnabled = false;
boolean doHysplit = true;
float trcrSize = 1f;
boolean trcrEnabled;
int numIntrpPts;
int trajSkip;
TrajectoryParams.SmoothParams smoothParams;
int direction;
int trajForm = LINE; // Default
float cylWidth = 0.01f;
float ribbonWidthFac = 1f;
int zStart = 0;
int zSkip = 0;
float[] intrpU;
float[] intrpV;
float[] intrpW;
float[] intrpU_1;
float[] intrpV_1;
float[] intrpW_1;
CubicInterpolator uInterp;
CubicInterpolator vInterp;
CubicInterpolator wInterp;
float[][] values0;
float[][] values1;
float[][] values2;
float[][] values3;
float[][] values0_last;
RealTupleType startPointType = Display.DisplaySpatialCartesianTuple;
ScalarMap altToZ;
ArrayList<FlowInfo> flowInfoList;
ArrayList<Trajectory> trajectories;
//- Listener per FlowControl for ProjectionControl events to auto resize tracer geometry.
public static HashMap<FlowControl, ControlListener> scaleChangeListeners = new HashMap<FlowControl, ControlListener>();
// Listener for ScalarMapControlEvent.CONTROL_REMOVED to remove above classes for garbage collection.
public static HashMap<ScalarMap, ScalarMapListener> removeListeners = new HashMap<ScalarMap, ScalarMapListener>();
public TrajectoryManager(DataRenderer renderer, TrajectoryParams trajParams, ArrayList<FlowInfo> flowInfoList, int dataDomainLength, double time) throws VisADException {
this(renderer, trajParams, flowInfoList, dataDomainLength, time, null);
}
public TrajectoryManager(DataRenderer renderer, TrajectoryParams trajParams, ArrayList<FlowInfo> flowInfoList, int dataDomainLength, double time, ScalarMap altToZ) throws VisADException {
this.flowInfoList = flowInfoList;
this.dataDomainLength = dataDomainLength;
trajVisibilityTimeWindow = trajParams.getTrajVisibilityTimeWindow();
trajRefreshInterval = trajParams.getTrajRefreshInterval();
trajLifetime = trajRefreshInterval; // Default. Should be greater than or equal to refresh interval
manualIntrpPts = trajParams.getManualIntrpPts();
numIntrpPts = trajParams.getNumIntrpPts();
trajSkip = trajParams.getStartSkip();
smoothParams = trajParams.getSmoothParams();
direction = trajParams.getDirection();
startPts = trajParams.getStartPoints();
trajDoIntrp = trajParams.getDoIntrp();
trcrSize = trajParams.getMarkerSize();
trcrEnabled = trajParams.getMarkerEnabled();
trajCachingEnabled = trajParams.getCachingEnabled();
trajForm = trajParams.getTrajectoryForm();
cylWidth = trajParams.getCylinderWidth();
ribbonWidthFac = trajParams.getRibbonWidthFactor();
zStart = trajParams.getZStartIndex();
zSkip = trajParams.getZStartSkip();
startPointType = trajParams.getStartType();
if (!trajDoIntrp) {
numIntrpPts = 1;
}
this.altToZ = altToZ;
FlowInfo info = flowInfoList.get(0);
Gridded3DSet spatial_set0 = (Gridded3DSet) info.spatial_set;
GriddedSet spatialSetTraj = makeSpatialSetTraj(spatial_set0);
byte[][] color_values = info.color_values;
if (info.trajColors != null) color_values = info.trajColors;
clrDim = color_values.length;
numSpatialPts = spatial_set0.getLength();
markGrid = new boolean[numSpatialPts];
markGridTime = new int[numSpatialPts];
java.util.Arrays.fill(markGrid, false);
java.util.Arrays.fill(markGridTime, 0);
startClrs = new byte[clrDim][];
if (startPts == null) {
try {
startPts = getStartPointsFromFile(renderer, altToZ, startClrs);
}
catch (Exception e) {
e.printStackTrace();
}
}
if (startPts == null) { //get from domain set
float[][] vec;
if (true) {
float[][] flowVals = convertFlowUnit(info.flow_values, info.flow_units);
vec = ShadowType.adjustFlowToEarth(info.which, flowVals, spatial_set0.getSamples(false), 1f, renderer);
}
startPts = new float[3][];
getStartPointsFromDomain(trajForm, trajSkip, zStart, zSkip, spatial_set0, color_values, startPts, startClrs, vec, ribbonWidthFac);
}
else {
int[] clrIdxs;
if (spatialSetTraj.getManifoldDimension() == 2) {
clrIdxs = spatialSetTraj.valueToIndex(new float[][] {startPts[0], startPts[1]});
} else {
clrIdxs = spatialSetTraj.valueToIndex(startPts);
}
int num = clrIdxs.length;
startClrs[0] = new byte[num];
startClrs[1] = new byte[num];
startClrs[2] = new byte[num];
if (clrDim == 4) startClrs[3] = new byte[num];
for (int i=0; i<num; i++) {
int clrIdx = clrIdxs[i];
if (clrIdx < 0) continue;
startClrs[0][i] = color_values[0][clrIdx];
startClrs[1][i] = color_values[1][clrIdx];
startClrs[2][i] = color_values[2][clrIdx];
if (clrDim == 4) startClrs[3][i] = color_values[3][clrIdx];
}
}
intrpU = new float[numSpatialPts];
intrpV = new float[numSpatialPts];
intrpW = new float[numSpatialPts];
if (doHysplit) {
intrpU_1 = new float[numSpatialPts];
intrpV_1 = new float[numSpatialPts];
intrpW_1 = new float[numSpatialPts];
}
uInterp = new CubicInterpolator(trajDoIntrp, numSpatialPts);
vInterp = new CubicInterpolator(trajDoIntrp, numSpatialPts);
wInterp = new CubicInterpolator(trajDoIntrp, numSpatialPts);
values0 = null;
values1 = null;
values2 = null;
values3 = null;
values0_last = null;
/* initialize and create a Trajectory for each start point */
trajectories = new ArrayList<Trajectory>();
java.util.Arrays.fill(markGrid, false);
makeTrajectories(direction*time, startPts, startClrs, spatialSetTraj);
}
public void addPair(float[] startPt, float[] stopPt, byte[] startColor, byte[] stopColor) {
coordinates[coordCnt++] = startPt[0];
coordinates[coordCnt++] = startPt[1];
coordinates[coordCnt++] = startPt[2];
vertCnt++;
coordinates[coordCnt++] = stopPt[0];
coordinates[coordCnt++] = stopPt[1];
coordinates[coordCnt++] = stopPt[2];
vertCnt++;
totNpairs++;
int clrDim = startColor.length;
colors[colorCnt++] = startColor[0];
colors[colorCnt++] = startColor[1];
colors[colorCnt++] = startColor[2];
if (clrDim == 4) {
colors[colorCnt++] = startColor[3];
}
colors[colorCnt++] = stopColor[0];
colors[colorCnt++] = stopColor[1];
colors[colorCnt++] = stopColor[2];
if (clrDim == 4) {
colors[colorCnt++] = stopColor[3];
}
}
public int getCoordinateCount() {
return coordCnt;
}
public int getColorCount() {
return colorCnt;
}
public int getNumberOfTrajectories() {
return trajectories.size();
}
public static int getNumIntrpPts(FlowInfo info, float maxSpd, double timeStep) throws VisADException {
int numIntrpPts;
float[][] del = computeDisplacement(info, new float[][] {{0f}, {0f}, {0f}}, new float[][] {{maxSpd},{0f},{0f}}, (float)timeStep);
double intrvl = (del[0][0]/0.10);
if (intrvl < 2) {
numIntrpPts = 2;
}
else {
numIntrpPts = (int) intrvl;
}
return numIntrpPts;
}
public static float[][] computeDisplacement(FlowInfo info, float[][] spatial_values, float[][] flow_values, float timeStep) throws VisADException {
return ShadowType.adjustFlowToEarth(info.which, flow_values, spatial_values, info.flowScale,
info.renderer, false, true, timeStep);
}
public VisADGeometryArray computeTrajectories(int k, double timeAccum, double[] times, double[] timeSteps, VisADGeometryArray[] auxArray) throws VisADException, RemoteException {
int i = (direction < 0) ? ((dataDomainLength-1) - k) : k;
VisADGeometryArray array = null;
FlowInfo info = flowInfoList.get(i);
byte[][] color_values = info.color_values;
Gridded3DSet spatial_set = (Gridded3DSet) info.spatial_set;
GriddedSet spatialSetTraj = makeSpatialSetTraj(spatial_set);
if (!manualIntrpPts && trajDoIntrp) {
numIntrpPts = getNumIntrpPts(info, 50f, timeSteps[i]);
}
float timeStep = (float) timeSteps[i]/numIntrpPts;
if ((timeAccum >= trajRefreshInterval)) { // for non steady state trajectories (refresh frequency)
trajectories = new ArrayList<Trajectory>();
java.util.Arrays.fill(markGrid, false);
makeTrajectories(direction*times[i], startPts, startClrs, spatialSetTraj);
}
if (trajForm == POINT) {
array = makePointGeometry();
}
// commented out when not using markGrid logic for starting/ending trajs
//Trajectory.makeTrajectories(times[i], trajectories, 6, color_values, setLocs, lens);
/*
Trajectory.checkTime(i); // for steady-state only
if ((i % 4) == 0) { // use for steady-state wind field
Trajectory.makeTrajectories(direction*times[i], trajectories, trajSkip, color_values, setLocs, lens);
}
*/
double x0 = (double) direction*i;
double x1 = (double) direction*(i+direction*1);
double x2 = (double) direction*(i+direction*2);
double x3 = (double) direction*(i+direction*3);
FlowInfo flwInfo;
if (k == 0) {
flwInfo = flowInfoList.get(i);
values0 = convertFlowUnit(flwInfo.flow_values, flwInfo.flow_units);
flwInfo = flowInfoList.get(i+direction*1);
values1 = convertFlowUnit(flwInfo.flow_values, flwInfo.flow_units);
flwInfo = flowInfoList.get(i+direction*2);
values2 = convertFlowUnit(flwInfo.flow_values, flwInfo.flow_units);
}
if (k < dataDomainLength-3) {
flwInfo = flowInfoList.get(i+direction*3);
values3 = convertFlowUnit(flwInfo.flow_values, flwInfo.flow_units);
}
if (values0_last != null) {
values0 = smooth(values0_last, values0, values1, smoothParams);
}
values1 = smooth(values0, values1, values2, smoothParams);
values2 = smooth(values1, values2, values3, smoothParams);
// ------- end smoothing
// update interpolator
if (k < dataDomainLength-2) {
uInterp.next(x0, x1, x2, values0[0], values1[0], values2[0]);
vInterp.next(x0, x1, x2, values0[1], values1[1], values2[1]);
wInterp.next(x0, x1, x2, values0[2], values1[2], values2[2]);
}
int numTrajectories = trajectories.size();
reset();
for (int ti=0; ti<numIntrpPts; ti++) { // additional points per domain time step
double dst = (x1 - x0)/numIntrpPts;
double xt = x0 + dst*ti;
updateInterpolators();
uInterp.interpolate(xt, intrpU);
vInterp.interpolate(xt, intrpV);
wInterp.interpolate(xt, intrpW);
if (doHysplit) { // NOAA HySplit
if (ti == numIntrpPts-1) {
System.arraycopy(values1[0], 0, intrpU_1, 0, intrpU_1.length);
System.arraycopy(values1[1], 0, intrpV_1, 0, intrpV_1.length);
System.arraycopy(values1[2], 0, intrpW_1, 0, intrpW_1.length);
}
else {
uInterp.interpolate(xt+dst, intrpU_1);
vInterp.interpolate(xt+dst, intrpV_1);
wInterp.interpolate(xt+dst, intrpW_1);
}
intrpU = mean(intrpU, intrpU_1);
intrpV = mean(intrpV, intrpV_1);
intrpW = mean(intrpW, intrpW_1);
}
for (int t=0; t<numTrajectories; t++) {
Trajectory traj = trajectories.get(t);
traj.currentTimeIndex = direction*i;
traj.currentTime = direction*times[i];
traj.forward(info, new float[][] {intrpU, intrpV, intrpW}, color_values, spatialSetTraj, direction, timeStep);
}
} // inner time loop (time interpolation)
values0_last = values0;
values0 = values1;
values1 = values2;
values2 = values3;
switch (trajForm) {
case LINE:
array = makeGeometry();
clean();
break;
case RIBBON:
array = makeFixedWidthRibbon();
clean();
break;
case CYLINDER:
array = makeCylinder(auxArray);
clean();
break;
case DEFORM_RIBBON:
array = makeDeformableRibbon();
cleanDefStrp();
break;
}
return array;
}
public void makeTrajectories(double time, float[][] startPts, byte[][] color_values, GriddedSet spatial_set) throws VisADException {
int num = startPts[0].length;
clrDim = color_values.length;
// determine grid relative positions of start points
int manifoldDimension = spatial_set.getManifoldDimension();
int[][] indices = new int[num][];
float[][] weights = new float[num][];
if (manifoldDimension == 2) {
spatial_set.valueToInterp(new float[][] {startPts[0], startPts[1]}, indices, weights);
}
else if (manifoldDimension == 3) {
spatial_set.valueToInterp(new float[][] {startPts[0], startPts[1], startPts[2]}, indices, weights);
}
for (int k=0; k<num; k++) {
// initialize a new trajectory
float startX = startPts[0][k];
float startY = startPts[1][k];
float startZ = startPts[2][k];
byte[] startColor = new byte[clrDim];
startColor[0] = color_values[0][k];
startColor[1] = color_values[1][k];
startColor[2] = color_values[2][k];
if (clrDim == 4) {
startColor[3] = color_values[3][k];
}
if (indices[k] != null) {
Trajectory traj = new Trajectory(this, startX, startY, startZ, indices[k], weights[k], startColor, time);
trajectories.add(traj);
}
}
}
/* Set internal counters to zero. Replace internal arrays and initialize to NaN. */
public void reset() {
int numTrajectories = trajectories.size();
int maxNumVerts = numTrajectories*numIntrpPts;
coordCnt = 0;
colorCnt = 0;
vertCnt = 0;
totNpairs = 0;
maxNumVerts *= 2; // one each for start and stop
if (coordinates == null || coordinates.length != 3*maxNumVerts) {
coordinates = new float[3*maxNumVerts];
}
if (colors == null || colors.length != clrDim*maxNumVerts) {
colors = new byte[clrDim*maxNumVerts];
}
java.util.Arrays.fill(coordinates, Float.NaN);
java.util.Arrays.fill(colors, (byte)0);
/* reset instance pair counter to zero */
for (int k=0; k<trajectories.size(); k++) {
Trajectory traj = trajectories.get(k);
traj.npairs = 0;
}
}
/* For steady-state trajectories (animated streamlines) only */
public void checkTime(int timeIdx) {
for (int k=0; k<markGridTime.length; k++) {
if ((timeIdx - markGridTime[k]) > 4) {
markGridTime[k] = timeIdx;
markGrid[k] = false;
}
}
}
/* Remove trajectories from list:
(1) That have left the grid (marked offGrid).
(2) That have time length (duration) greater than some threshold.
*/
public void clean() {
ArrayList<Trajectory> newList = new ArrayList<Trajectory>();
Iterator<Trajectory> iter = trajectories.iterator();
while (iter.hasNext() ) {
Trajectory traj = iter.next();
if (!traj.offGrid && ((traj.currentTime - traj.initialTime) < trajLifetime)) {
newList.add(traj);
}
}
trajectories = newList;
}
public void cleanDefStrp() {
Iterator<Trajectory> iter = trajectories.iterator();
ArrayList<Trajectory> removeList = new ArrayList<Trajectory>();
while (iter.hasNext() ) {
Trajectory traj = iter.next();
if (traj.offGrid || ((traj.currentTime - traj.initialTime) > trajLifetime)) {
int idxA;
int idxB;
int idx = trajectories.indexOf(traj);
if ((idx % 2) == 0) {
idxA = idx;
idxB = idx+1;
}
else {
idxB = idx;
idxA = idx-1;
}
removeList.add(trajectories.get(idxA));
removeList.add(trajectories.get(idxB));
}
}
for (int t=0; t<removeList.size(); t++) {
trajectories.remove(removeList.get(t));
}
}
public void updateInterpolators() {
boolean[] needed = new boolean[numSpatialPts];
java.util.Arrays.fill(needed, false);
for (int k=0; k<trajectories.size(); k++) {
Trajectory traj = trajectories.get(k);
if (!traj.offGrid) {
int[] cell = traj.startCell;
for (int t=0; t<cell.length; t++) {
needed[cell[t]] = true;
}
}
}
uInterp.update(needed);
vInterp.update(needed);
wInterp.update(needed);
}
public static GriddedSet makeSpatialSetTraj(Gridded3DSet spatial_set) throws VisADException {
int manifoldDim = spatial_set.getManifoldDimension();
int[] lens = spatial_set.getLengths();
float[][] setLocs = spatial_set.getSamples(false);
GriddedSet spatialSetTraj;
if (manifoldDim == 2) {
spatialSetTraj = new Gridded2DSet(RealTupleType.SpatialCartesian2DTuple,
new float[][] {setLocs[0], setLocs[1]}, lens[0], lens[1]);
} else {
spatialSetTraj = spatial_set;
}
return spatialSetTraj;
}
public static double[] getScale(MouseBehavior mouseBehav, ProjectionControl pCntrl) {
double[] matrix = pCntrl.getMatrix();
double[] rot = new double[3];
double[] trans = new double[3];
double[] scale = new double[3];
mouseBehav.instance_unmake_matrix(rot, scale, trans, matrix);
return scale;
}
public void getStartPointsFromDomain(int trajForm, int skip, int zstart, int zskip, Gridded3DSet spatial_set, byte[][] color_values, float[][] startPts, byte[][] startClrs, float[][] flowValues, float ribbonWidthFac) throws VisADException {
int manifoldDim = spatial_set.getManifoldDimension();
int[] lens = spatial_set.getLengths();
int lenX = lens[0];
int lenY = lens[1];
int lenZ;
if (manifoldDim == 3) {
lenZ = lens[2];
if (zskip <= 0) {
zskip = 1;
}
getStartPointsFromDomain3D(trajForm, skip, zstart, zskip, spatial_set.getSamples(false), lenX, lenY, lenZ, color_values, startPts, startClrs, flowValues, ribbonWidthFac);
}
else if (manifoldDim == 2) {
getStartPointsFromDomain2D(trajForm, skip, spatial_set.getSamples(false), lenX, lenY, color_values, startPts, startClrs, flowValues, ribbonWidthFac);
}
}
public void getStartPointsFromDomain3D(int trajForm, int skip, int zstart, int skipZ, float[][] locs, int lenX, int lenY, int lenZ, byte[][] color_values, float[][] startPts, byte[][] startClrs, float[][] flowValues, float ribbonWidthFac) throws VisADException {
int len2D = lenX*lenY;
float[][] locs2D = new float[3][len2D];
float[][] pts = new float[3][];
int clrDim = startClrs.length;
byte[][] clrs2D = new byte[clrDim][len2D];
byte[][] clrs = new byte[clrDim][];
int lenA = 0;
for (int k=zstart; k<lenZ; k+=skipZ) {
System.arraycopy(locs[0], k*len2D, locs2D[0], 0, len2D);
System.arraycopy(locs[1], k*len2D, locs2D[1], 0, len2D);
System.arraycopy(locs[2], k*len2D, locs2D[2], 0, len2D);
System.arraycopy(color_values[0], k*len2D, clrs2D[0], 0, len2D);
System.arraycopy(color_values[1], k*len2D, clrs2D[1], 0, len2D);
System.arraycopy(color_values[2], k*len2D, clrs2D[2], 0, len2D);
if (clrDim == 4) {
System.arraycopy(color_values[3], k*len2D, clrs2D[3], 0, len2D);
}
getStartPointsFromDomain2D(trajForm, skip, locs2D, lenX, lenY, clrs2D, pts, clrs, flowValues, ribbonWidthFac);
int lenB = pts[0].length;
float[][] tmpPts = new float[3][lenA+lenB];
byte[][] tmpClrs = new byte[clrDim][lenA+lenB];
if (lenA > 0) {
System.arraycopy(startPts[0], 0, tmpPts[0], 0, lenA);
System.arraycopy(startPts[1], 0, tmpPts[1], 0, lenA);
System.arraycopy(startPts[2], 0, tmpPts[2], 0, lenA);
System.arraycopy(startClrs[0], 0, tmpClrs[0], 0, lenA);
System.arraycopy(startClrs[1], 0, tmpClrs[1], 0, lenA);
System.arraycopy(startClrs[2], 0, tmpClrs[2], 0, lenA);
if (clrDim == 4) {
System.arraycopy(startClrs[3], 0, tmpClrs[3], 0, lenA);
}
}
System.arraycopy(pts[0], 0, tmpPts[0], lenA, lenB);
System.arraycopy(pts[1], 0, tmpPts[1], lenA, lenB);
System.arraycopy(pts[2], 0, tmpPts[2], lenA, lenB);
System.arraycopy(clrs[0], 0, tmpClrs[0], lenA, lenB);
System.arraycopy(clrs[1], 0, tmpClrs[1], lenA, lenB);
System.arraycopy(clrs[2], 0, tmpClrs[2], lenA, lenB);
if (clrDim == 4) {
System.arraycopy(clrs[3], 0, tmpClrs[3], lenA, lenB);
}
startPts[0] = tmpPts[0];
startPts[1] = tmpPts[1];
startPts[2] = tmpPts[2];
startClrs[0] = tmpClrs[0];
startClrs[1] = tmpClrs[1];
startClrs[2] = tmpClrs[2];
if (clrDim == 4) {
startClrs[3] = tmpClrs[3];
}
lenA = startPts[0].length;
}
}
public void getStartPointsFromDomain2D(int trajForm, int skip, float[][] setLocs, int lenX, int lenY, byte[][] color_values, float[][] startPts, byte[][] startClrs, float[][] flowValues, float ribbonWidthFac) throws VisADException {
int clrDim = color_values.length;
int m = 0;
if (doStartOffset) {
m = cnt % 4;
cnt++;
}
int jA = 1+o_j[m]*(skip/2);
int jB = lenY-skip;
int iA = 1+o_i[m]*(skip/2);
int iB = lenX-skip;
int numJ = 1 + ((jB-1)-jA)/skip;
int numI = 1 + ((iB-1)-iA)/skip;
int num = numJ*numI;
if (trajForm == TrajectoryParams.DEFORM_RIBBON) {
num *= 2;
}
startPts[0] = new float[num];
startPts[1] = new float[num];
startPts[2] = new float[num];
startClrs[0] = new byte[num];
startClrs[1] = new byte[num];
startClrs[2] = new byte[num];
if (clrDim == 4) {
startClrs[3] = new byte[num];
}
float[] norm = new float[] {0f, 0f, 1f};
float[] traj = new float[3];
float width = ribbonWidthFac*0.006f;
num = 0;
for (int j=1+o_j[m]*(skip/2); j<lenY-skip; j+=skip) {
for (int i=1+o_i[m]*(skip/2); i<lenX-skip; i+=skip) {
int k = j*lenX + i;
if (trajForm == TrajectoryParams.DEFORM_RIBBON) {
float u = flowValues[0][k];
float v = flowValues[1][k];
traj[0] = u;
traj[1] = v;
traj[2] = 0f;
float mag = (float) Math.sqrt(u*u+v*v);
traj[0] /= mag;
traj[1] /= mag;
float[] norm_x_traj = AxB(norm, traj);
if (!markGrid[k]) {
startPts[0][num] = width*norm_x_traj[0] + setLocs[0][k];
startPts[1][num] = width*norm_x_traj[1] + setLocs[1][k];
startPts[2][num] = width*norm_x_traj[2] + setLocs[2][k];
startClrs[0][num] = color_values[0][k];
startClrs[1][num] = color_values[1][k];
startClrs[2][num] = color_values[2][k];
if (clrDim == 4) {
startClrs[3][num] = color_values[3][k];
}
num++;
startPts[0][num] = -width*norm_x_traj[0] + setLocs[0][k];
startPts[1][num] = -width*norm_x_traj[1] + setLocs[1][k];
startPts[2][num] = -width*norm_x_traj[2] + setLocs[2][k];
startClrs[0][num] = color_values[0][k];
startClrs[1][num] = color_values[1][k];
startClrs[2][num] = color_values[2][k];
if (clrDim == 4) {
startClrs[3][num] = color_values[3][k];
}
num++;
}
}
else {
if (!markGrid[k]) {
startPts[0][num] = setLocs[0][k];
startPts[1][num] = setLocs[1][k];
startPts[2][num] = setLocs[2][k];
startClrs[0][num] = color_values[0][k];
startClrs[1][num] = color_values[1][k];
startClrs[2][num] = color_values[2][k];
if (clrDim == 4) {
startClrs[3][num] = color_values[3][k];
}
num++;
}
}
}
}
/* For animated Streamllines TODO
for (int k=0; k<markGrid.length; k++) {
markGrid[k] = false;
}
*/
}
public static float[][] convertFlowUnit(float[][] values, Unit[] units) throws VisADException {
// Flow units must be convertible to m s-1 for trajectory computation
Unit meterPerSecond = CommonUnit.meterPerSecond;
float[] valsX = values[0];
if (Unit.canConvert(units[0], meterPerSecond)) {
valsX = meterPerSecond.toThis(values[0], units[0]);
}
float[] valsY = values[1];
if (Unit.canConvert(units[1], meterPerSecond)) {
valsY = meterPerSecond.toThis(values[1], units[1]);
}
float[] valsZ = values[2];
if (Unit.canConvert(units[2], meterPerSecond)) {
valsZ = meterPerSecond.toThis(values[2], units[2]);
}
return new float[][] {valsX, valsY, valsZ};
}
public static float[][] smooth(float[][] values0, float[][] values1, float[][] values2, TrajectoryParams.SmoothParams smoothParams) {
if (smoothParams.equals(TrajectoryParams.SmoothParams.NONE)) {
return values1;
}
float w0 = smoothParams.w0;
float w1 = smoothParams.w1;
float w2 = smoothParams.w2;
int numPts = values0[0].length;
float[][] new_values = new float[3][numPts];
for (int k=0; k<numPts; k++) {
new_values[0][k] = w0*values0[0][k] + w1*values1[0][k] + w2*values2[0][k];
new_values[1][k] = w0*values0[1][k] + w1*values1[1][k] + w2*values2[1][k];
new_values[2][k] = w0*values0[2][k] + w1*values1[2][k] + w2*values2[2][k];
}
return new_values;
}
public static float[][] mean(float[][] values0, float[][] values1) {
int numPts = values0[0].length;
float[][] meanValues = new float[3][numPts];
for (int k=0; k<numPts; k++) {
meanValues[0][k] = (values0[0][k] + values1[0][k])/2;
meanValues[1][k] = (values0[1][k] + values1[1][k])/2;
meanValues[2][k] = (values0[2][k] + values1[2][k])/2;
}
return meanValues;
}
public static float[] mean(float[] values0, float[] values1) {
int numPts = values0.length;
float[] meanValues = new float[numPts];
for (int k=0; k<numPts; k++) {
meanValues[k] = (values0[k] + values1[k])/2;
}
return meanValues;
}
public void setListener(ProjectionControl pCntrl, ControlListener listener, FlowControl flowCntrl) {
if (scaleChangeListeners.containsKey(flowCntrl)) {
ControlListener value = scaleChangeListeners.get(flowCntrl);
pCntrl.removeControlListener(value);
scaleChangeListeners.put(flowCntrl, listener);
}
else {
scaleChangeListeners.put(flowCntrl, listener);
}
pCntrl.addControlListener(listener);
}
public static double[] getTimeSteps(Gridded1DSet timeSet) throws VisADException {
double[] timePts;
if (timeSet instanceof Gridded1DDoubleSet) {
timePts = (timeSet.getDoubles())[0];
}
else {
timePts = (Set.floatToDouble(timeSet.getSamples()))[0];
}
double[] timeSteps = new double[timePts.length];
Unit[] setUnits = timeSet.getSetUnits();
timePts = CommonUnit.secondsSinceTheEpoch.toThis(timePts, setUnits[0]);
for (int t=0; t<timePts.length-1; t++) {
timeSteps[t] = timePts[t+1]-timePts[t];
}
timeSteps[timePts.length-1] = timeSteps[timePts.length-2];
return timeSteps;
}
public static double[] getTimes(Gridded1DSet timeSet) throws VisADException {
double[] timePts;
if (timeSet instanceof Gridded1DDoubleSet) {
timePts = (timeSet.getDoubles())[0];
}
else {
timePts = (Set.floatToDouble(timeSet.getSamples()))[0];
}
Unit[] setUnits = timeSet.getSetUnits();
timePts = CommonUnit.secondsSinceTheEpoch.toThis(timePts, setUnits[0]);
return timePts;
}
public static VisADGeometryArray scaleGeometry(VisADGeometryArray array, ArrayList<float[]> anchors, float scale) {
int nShapes = anchors.size();
int numVertsPerShape = array.vertexCount/nShapes;
VisADGeometryArray scldArray = new VisADTriangleArray();
scldArray.coordinates = new float[3*array.vertexCount];
scldArray.colors = array.colors;
scldArray.normals = array.normals;
scldArray.vertexCount = array.vertexCount;
for (int k=0; k<nShapes; k++) {
float[] ancrPt = anchors.get(k);
for (int t=0; t<numVertsPerShape; t++) {
int idx = k*numVertsPerShape*3 + 3*t;
float x0 = array.coordinates[idx];
float y0 = array.coordinates[idx + 1];
float z0 = array.coordinates[idx + 2];
float x1 = (x0 - ancrPt[0])*scale;
float y1 = (y0 - ancrPt[1])*scale;
float z1 = (z0 - ancrPt[2])*scale;
scldArray.coordinates[idx] = x1 + ancrPt[0];
scldArray.coordinates[idx+1] = y1 + ancrPt[1];
scldArray.coordinates[idx+2] = z1 + ancrPt[2];
}
}
return scldArray;
}
public static float[] AxB(float[] A, float[] B) {
float[] axb = new float[3];
axb[0] = A[1] * B[2] - A[2] * B[1];
axb[1] = -(A[0] * B[2] - A[2] * B[0]);
axb[2] = A[0] * B[1] - A[1] * B[0];
return axb;
}
public static float AdotB(float[] A, float[] B) {
float ab = A[0]*B[0] + A[1]*B[1] + A[2]*B[2];
return ab;
}
public static double[] getRotatedVecInPlane(double[] T, double[] S, double[] P, double[] V, double theta, double[] rotV) {
if (rotV == null) rotV = new double[3];
double s = V[0]*Math.cos(theta) + V[1]*Math.sin(theta);
double t = V[0]*Math.sin(theta) + V[1]*Math.cos(theta);
double x = P[0] + s*S[0] + t*T[0];
double y = P[1] + s*S[1] + t*T[1];
double z = P[2] + s*S[2] + t*T[2];
rotV[0] = x;
rotV[1] = y;
rotV[2] = z;
return rotV;
}
public VisADGeometryArray makeGeometry() {
VisADLineArray array = new VisADLineArray();
float[] newCoords = new float[coordCnt];
byte[] newColors = new byte[colorCnt];
System.arraycopy(coordinates, 0, newCoords, 0, newCoords.length);
System.arraycopy(colors, 0, newColors, 0, newColors.length);
array.coordinates = newCoords;
array.colors = newColors;
array.vertexCount = vertCnt;
return array;
}
public VisADGeometryArray makeFixedWidthRibbon() {
VisADTriangleArray array = new VisADTriangleArray();
int ntrajs = trajectories.size();
int num = totNpairs*6;
float[] newCoords = new float[num*3*2];
byte[] newColors = new byte[num*clrDim*2];
float[] newNormals = new float[num*3*2];
float[] uvecPath = new float[3];
float[] ptA = new float[3];
float[] ptB = new float[3];
float[] ptC = new float[3];
float[] ptD = new float[3];
float[] ptAA = new float[3];
float[] ptBB = new float[3];
float[] ptCC = new float[3];
float[] ptDD = new float[3];
float[] norm = new float[] {0f, 0f, 1f};
int numVert=0;
byte r0,g0,b0,r1,g1,b1;
byte a0 = -1;
byte a1 = -1;
float width = ribbonWidthFac*0.006f;
for (int t=0; t<ntrajs; t++) {
Trajectory traj = trajectories.get(t);
for (int k=0; k<traj.npairs; k++) {
int i = traj.indexes[k];
int ci = 2*clrDim*i/6;
float x0 = coordinates[i];
float y0 = coordinates[i+1];
float z0 = coordinates[i+2];
float x1 = coordinates[i+3];
float y1 = coordinates[i+4];
float z1 = coordinates[i+5];
if (clrDim == 3) {
r0 = colors[ci];
g0 = colors[ci+1];
b0 = colors[ci+2];
r1 = colors[ci+3];
g1 = colors[ci+4];
b1 = colors[ci+5];
}
else {
r0 = colors[ci];
g0 = colors[ci+1];
b0 = colors[ci+2];
a0 = colors[ci+3];
r1 = colors[ci+4];
g1 = colors[ci+5];
b1 = colors[ci+6];
a1 = colors[ci+7];
}
float mag = (x1-x0)*(x1-x0) + (y1-y0)*(y1-y0) + (z1-z0)*(z1-z0);
mag = (float) Math.sqrt(mag);
uvecPath[0] = (x1-x0)/mag;
uvecPath[1] = (y1-y0)/mag;
uvecPath[2] = (z1-z0)/mag;
float[] norm_x_trj = AxB(norm, uvecPath);
float[] trj_x_norm_x_trj = AxB(uvecPath, norm_x_trj);
// fixed width ribbon. Horz: A,B,C,D Vert: AA,BB,CC,DD ----------------------
if (k==0) {
if (traj.lastPtC == null) {
ptA[0] = width*norm_x_trj[0] + x0;
ptA[1] = width*norm_x_trj[1] + y0;
ptA[2] = width*norm_x_trj[2] + z0;
ptB[0] = -width*norm_x_trj[0] + x0;
ptB[1] = -width*norm_x_trj[1] + y0;
ptB[2] = -width*norm_x_trj[2] + z0;
ptAA[0] = width*trj_x_norm_x_trj[0] + x0;
ptAA[1] = width*trj_x_norm_x_trj[1] + y0;
ptAA[2] = width*trj_x_norm_x_trj[2] + z0;
ptBB[0] = -width*trj_x_norm_x_trj[0] + x0;
ptBB[1] = -width*trj_x_norm_x_trj[1] + y0;
ptBB[2] = -width*trj_x_norm_x_trj[2] + z0;
}
else {
ptA[0] = traj.lastPtD[0];
ptA[1] = traj.lastPtD[1];
ptA[2] = traj.lastPtD[2];
ptB[0] = traj.lastPtC[0];
ptB[1] = traj.lastPtC[1];
ptB[2] = traj.lastPtC[2];
ptAA[0] = traj.lastPtDD[0];
ptAA[1] = traj.lastPtDD[1];
ptAA[2] = traj.lastPtDD[2];
ptBB[0] = traj.lastPtCC[0];
ptBB[1] = traj.lastPtCC[1];
ptBB[2] = traj.lastPtCC[2];
}
}
else {
ptA[0] = ptD[0];
ptA[1] = ptD[1];
ptA[2] = ptD[2];
ptB[0] = ptC[0];
ptB[1] = ptC[1];
ptB[2] = ptC[2];
ptAA[0] = ptDD[0];
ptAA[1] = ptDD[1];
ptAA[2] = ptDD[2];
ptBB[0] = ptCC[0];
ptBB[1] = ptCC[1];
ptBB[2] = ptCC[2];
}
ptD[0] = width*norm_x_trj[0] + x1;
ptD[1] = width*norm_x_trj[1] + y1;
ptD[2] = width*norm_x_trj[2] + z1;
ptC[0] = -width*norm_x_trj[0] + x1;
ptC[1] = -width*norm_x_trj[1] + y1;
ptC[2] = -width*norm_x_trj[2] + z1;
ptDD[0] = width*trj_x_norm_x_trj[0] + x1;
ptDD[1] = width*trj_x_norm_x_trj[1] + y1;
ptDD[2] = width*trj_x_norm_x_trj[2] + z1;
ptCC[0] = -width*trj_x_norm_x_trj[0] + x1;
ptCC[1] = -width*trj_x_norm_x_trj[1] + y1;
ptCC[2] = -width*trj_x_norm_x_trj[2] + z1;
if (traj.lastPtD == null) {
traj.lastPtC = new float[] {ptC[0], ptC[1], ptC[2]};
traj.lastPtD = new float[] {ptD[0], ptD[1], ptD[2]};
traj.lastPtCC = new float[] {ptCC[0], ptCC[1], ptCC[2]};
traj.lastPtDD = new float[] {ptDD[0], ptDD[1], ptDD[2]};
}
else {
traj.lastPtC[0] = ptC[0];
traj.lastPtC[1] = ptC[1];
traj.lastPtC[2] = ptC[2];
traj.lastPtD[0] = ptD[0];
traj.lastPtD[1] = ptD[1];
traj.lastPtD[2] = ptD[2];
traj.lastPtCC[0] = ptCC[0];
traj.lastPtCC[1] = ptCC[1];
traj.lastPtCC[2] = ptCC[2];
traj.lastPtDD[0] = ptDD[0];
traj.lastPtDD[1] = ptDD[1];
traj.lastPtDD[2] = ptDD[2];
}
int idx = numVert*3;
int cidx = numVert*clrDim;
newCoords[idx] = ptA[0];
newCoords[idx+1] = ptA[1];
newCoords[idx+2] = ptA[2];
newColors[cidx] = r0;
newColors[cidx+1] = g0;
newColors[cidx+2] = b0;
if (clrDim == 4) newColors[cidx+3] = a0;
newNormals[idx] = 0f;
newNormals[idx+1] = 0f;
newNormals[idx+2] = 1f;
numVert++;
idx = numVert*3;
cidx = numVert*clrDim;
newCoords[idx] = ptB[0];
newCoords[idx+1] = ptB[1];
newCoords[idx+2] = ptB[2];
newColors[cidx] = r0;
newColors[cidx+1] = g0;
newColors[cidx+2] = b0;
if (clrDim == 4) newColors[cidx+3] = a0;
newNormals[idx] = 0f;
newNormals[idx+1] = 0f;
newNormals[idx+2] = 1f;
numVert++;
idx = numVert*3;
cidx = numVert*clrDim;
newCoords[idx] = ptC[0];
newCoords[idx+1] = ptC[1];
newCoords[idx+2] = ptC[2];
newColors[cidx] = r1;
newColors[cidx+1] = g1;
newColors[cidx+2] = b1;
if (clrDim == 4) newColors[cidx+3] = a1;
newNormals[idx] = 0f;
newNormals[idx+1] = 0f;
newNormals[idx+2] = 1f;
numVert++;
idx = numVert*3;
cidx = numVert*clrDim;
newCoords[idx] = ptAA[0];
newCoords[idx+1] = ptAA[1];
newCoords[idx+2] = ptAA[2];
newColors[cidx] = r0;
newColors[cidx+1] = g0;
newColors[cidx+2] = b0;
if (clrDim == 4) newColors[cidx+3] = a0;
newNormals[idx] = norm_x_trj[0];
newNormals[idx+1] = norm_x_trj[1];
newNormals[idx+2] = norm_x_trj[2];
numVert++;
idx = numVert*3;
cidx = numVert*clrDim;
newCoords[idx] = ptBB[0];
newCoords[idx+1] = ptBB[1];
newCoords[idx+2] = ptBB[2];
newColors[cidx] = r0;
newColors[cidx+1] = g0;
newColors[cidx+2] = b0;
if (clrDim == 4) newColors[cidx+3] = a0;
newNormals[idx] = norm_x_trj[0];
newNormals[idx+1] = norm_x_trj[1];
newNormals[idx+2] = norm_x_trj[2];
numVert++;
idx = numVert*3;
cidx = numVert*clrDim;
newCoords[idx] = ptCC[0];
newCoords[idx+1] = ptCC[1];
newCoords[idx+2] = ptCC[2];
newColors[cidx] = r1;
newColors[cidx+1] = g1;
newColors[cidx+2] = b1;
if (clrDim == 4) newColors[cidx+3] = a1;
newNormals[idx] = norm_x_trj[0];
newNormals[idx+1] = norm_x_trj[1];
newNormals[idx+2] = norm_x_trj[2];
numVert++;
idx = numVert*3;
cidx = numVert*clrDim;
newCoords[idx] = ptC[0];
newCoords[idx+1] = ptC[1];
newCoords[idx+2] = ptC[2];
newColors[cidx] = r1;
newColors[cidx+1] = g1;
newColors[cidx+2] = b1;
if (clrDim == 4) newColors[cidx+3] = a1;
newNormals[idx] = 0f;
newNormals[idx+1] = 0f;
newNormals[idx+2] = 1f;
numVert++;
idx = numVert*3;
cidx = numVert*clrDim;
newCoords[idx] = ptA[0];
newCoords[idx+1] = ptA[1];
newCoords[idx+2] = ptA[2];
newColors[cidx] = r0;
newColors[cidx+1] = g0;
newColors[cidx+2] = b0;
if (clrDim == 4) newColors[cidx+3] = a0;
newNormals[idx] = 0f;
newNormals[idx+1] = 0f;
newNormals[idx+2] = 1f;
numVert++;
idx = numVert*3;
cidx = numVert*clrDim;
newCoords[idx] = ptD[0];
newCoords[idx+1] = ptD[1];
newCoords[idx+2] = ptD[2];
newColors[cidx] = r1;
newColors[cidx+1] = g1;
newColors[cidx+2] = b1;
if (clrDim == 4) newColors[cidx+3] = a1;
newNormals[idx] = 0f;
newNormals[idx+1] = 0f;
newNormals[idx+2] = 1f;
numVert++;
idx = numVert*3;
cidx = numVert*clrDim;
newCoords[idx] = ptCC[0];
newCoords[idx+1] = ptCC[1];
newCoords[idx+2] = ptCC[2];
newColors[cidx] = r1;
newColors[cidx+1] = g1;
newColors[cidx+2] = b1;
if (clrDim == 4) newColors[cidx+3] = a1;
newNormals[idx] = norm_x_trj[0];
newNormals[idx+1] = norm_x_trj[1];
newNormals[idx+2] = norm_x_trj[2];
numVert++;
idx = numVert*3;
cidx = numVert*clrDim;
newCoords[idx] = ptAA[0];
newCoords[idx+1] = ptAA[1];
newCoords[idx+2] = ptAA[2];
newColors[cidx] = r0;
newColors[cidx+1] = g0;
newColors[cidx+2] = b0;
if (clrDim == 4) newColors[cidx+3] = a0;
newNormals[idx] = norm_x_trj[0];
newNormals[idx+1] = norm_x_trj[1];
newNormals[idx+2] = norm_x_trj[2];
numVert++;
idx = numVert*3;
cidx = numVert*clrDim;
newCoords[idx] = ptDD[0];
newCoords[idx+1] = ptDD[1];
newCoords[idx+2] = ptDD[2];
newColors[cidx] = r1;
newColors[cidx+1] = g1;
newColors[cidx+2] = b1;
if (clrDim == 4) newColors[cidx+3] = a1;
newNormals[idx] = norm_x_trj[0];
newNormals[idx+1] = norm_x_trj[1];
newNormals[idx+2] = norm_x_trj[2];
numVert++;
// end ribbon construction -----------------------------
}
}
array.coordinates = newCoords;
array.normals = newNormals;
array.colors = newColors;
array.vertexCount = numVert;
return array;
}
public VisADGeometryArray makeCylinder(VisADGeometryArray[] auxArray) {
VisADTriangleStripArray array = new VisADTriangleStripArray();
VisADTriangleArray coneArray = new VisADTriangleArray();
int ntrajs = trajectories.size();
int numSides = 20;
int numv = totNpairs*(numSides+1)*2;
float[] coords = new float[numv*3];
byte[] newColors = new byte[numv*clrDim];
float[] normals = new float[numv*3];
int[] strips = new int[totNpairs];
float[] coneCoords = new float[ntrajs*(numSides+1)*3*3];
byte[] coneColors = new byte[ntrajs*(numSides+1)*3*clrDim];
float[] coneNormals = new float[ntrajs*(numSides+1)*3*3];
float[] uvecPath = new float[3];
byte[][] clr0 = new byte[clrDim][1];
byte[][] clr1 = new byte[clrDim][1];
float[] pt0 = new float[3];
float[] pt1 = new float[3];
float[][] basePts = new float[3][numSides+1];
int[] idx = new int[] {0};
int strpCnt = 0;
int[] coneIdx = new int[] {0};
byte r0,g0,b0,r1,g1,b1;
byte a0 = -1;
byte a1 = -1;
for (int t=0; t<ntrajs; t++) {
Trajectory traj = trajectories.get(t);
for (int k=0; k<traj.npairs; k++) {
int i = traj.indexes[k];
int ci = 2*clrDim*i/6;
float x0 = coordinates[i];
float y0 = coordinates[i+1];
float z0 = coordinates[i+2];
float x1 = coordinates[i+3];
float y1 = coordinates[i+4];
float z1 = coordinates[i+5];
if (clrDim == 3) {
r0 = colors[ci];
g0 = colors[ci+1];
b0 = colors[ci+2];
r1 = colors[ci+3];
g1 = colors[ci+4];
b1 = colors[ci+5];
}
else {
r0 = colors[ci];
g0 = colors[ci+1];
b0 = colors[ci+2];
a0 = colors[ci+3];
r1 = colors[ci+4];
g1 = colors[ci+5];
b1 = colors[ci+6];
a1 = colors[ci+7];
}
float mag = (x1-x0)*(x1-x0) + (y1-y0)*(y1-y0) + (z1-z0)*(z1-z0);
mag = (float) Math.sqrt(mag);
uvecPath[0] = (x1-x0)/mag;
uvecPath[1] = (y1-y0)/mag;
uvecPath[2] = (z1-z0)/mag;
float[] norm;
float[] norm_x_trj;
float[] trj_x_norm_x_trj;
if (traj.last_circleXYZ == null) {
norm = new float[] {0f, 0f, 1f};
norm_x_trj = AxB(norm, uvecPath);
trj_x_norm_x_trj = AxB(uvecPath, norm_x_trj);
}
else {
norm_x_trj = AxB(traj.lastTvec, uvecPath);
trj_x_norm_x_trj = AxB(uvecPath, norm_x_trj);
}
pt0[0] = x0;
pt0[1] = y0;
pt0[2] = z0;
pt1[0] = x1;
pt1[1] = y1;
pt1[2] = z1;
clr0[0][0] = r0;
clr0[1][0] = g0;
clr0[2][0] = b0;
if (clrDim == 4) clr0[3][0] = a0;
clr1[0][0] = r1;
clr1[1][0] = g1;
clr1[2][0] = b1;
if (clrDim == 4) clr1[3][0] = a1;
cylWidth = 0.0040f;
traj.makeCylinderStrip(trj_x_norm_x_trj, norm_x_trj, pt0, pt1, clr0, clr1, cylWidth, (numSides+1), coords, newColors, normals, idx);
strips[strpCnt++] = (numSides+1)*2;
}
float vFac = (float) (cylWidth/0.01);
float[] vertex = new float[3];
vertex[0] = pt1[0] + uvecPath[0]*0.006f*vFac;
vertex[1] = pt1[1] + uvecPath[1]*0.006f*vFac;
vertex[2] = pt1[2] + uvecPath[2]*0.006f*vFac;
// build cone here. add to coneArray
makeCone(traj.last_circleXYZ, vertex, clr0, coneCoords, coneColors, coneNormals, coneIdx);
}
array.coordinates = coords;
array.normals = normals;
array.colors = newColors;
array.vertexCount = idx[0];
array.stripVertexCounts = strips;
coneArray.coordinates = coneCoords;
coneArray.normals = coneNormals;
coneArray.colors = coneColors;
coneArray.vertexCount = coneIdx[0];
auxArray[0] = coneArray;
return array;
}
public void makeCone(float[][] basePts, float[] vertex, byte[][] color, float[] coords, byte[] colors, float[] normals, int[] vertCnt) {
int nPts = basePts[0].length;
float[] ptA = new float[3];
float[] ptB = new float[3];
float[] AV = new float[3];
float[] BV = new float[3];
int vcnt = vertCnt[0];
int idx = 3*vcnt;
int cidx = clrDim*vcnt;
for (int k=0; k<nPts; k++) {
// A--vertex--B
int ia = k;
int ib = (k==(nPts-1)) ? 0 : (k+1);
ptA[0] = basePts[0][ia];
ptA[1] = basePts[1][ia];
ptA[2] = basePts[2][ia];
ptB[0] = basePts[0][ib];
ptB[1] = basePts[1][ib];
ptB[2] = basePts[2][ib];
AV[0] = ptA[0] - vertex[0];
AV[1] = ptA[1] - vertex[1];
AV[2] = ptA[2] - vertex[2];
BV[0] = ptB[0] - vertex[0];
BV[1] = ptB[1] - vertex[1];
BV[2] = ptB[2] - vertex[2];
float[] norm = AxB(AV, BV);
float mag = (float) Math.sqrt(norm[0]*norm[0]+norm[1]*norm[1]+norm[2]*norm[2]);
norm[0] /= mag;
norm[1] /= mag;
norm[2] /= mag;
normals[idx] = norm[0];
coords[idx++] = ptA[0];
normals[idx] = norm[1];
coords[idx++] = ptA[1];
normals[idx] = norm[2];
coords[idx++] = ptA[2];
colors[cidx++] = color[0][0];
colors[cidx++] = color[1][0];
colors[cidx++] = color[2][0];
if (clrDim == 4) colors[cidx++] = color[3][0];
vcnt++;
normals[idx] = norm[0];
coords[idx++] = ptB[0];
normals[idx] = norm[1];
coords[idx++] = ptB[1];
normals[idx] = norm[2];
coords[idx++] = ptB[2];
colors[cidx++] = color[0][0];
colors[cidx++] = color[1][0];
colors[cidx++] = color[2][0];
if (clrDim == 4) colors[cidx++] = color[3][0];
vcnt++;
normals[idx] = norm[0];
coords[idx++] = vertex[0];
normals[idx] = norm[1];
coords[idx++] = vertex[1];
normals[idx] = norm[2];
coords[idx++] = vertex[2];
colors[cidx++] = color[0][0];
colors[cidx++] = color[1][0];
colors[cidx++] = color[2][0];
if (clrDim == 4) colors[cidx++] = color[3][0];
vcnt++;
}
vertCnt[0] = vcnt;
}
public VisADGeometryArray makeDeformableRibbon() {
VisADTriangleArray array = new VisADTriangleArray();
int ntrajs = trajectories.size();
int ntris = (totNpairs/2)*2;
int num = ntris*3;
float[] newCoords = new float[num*3];
java.util.Arrays.fill(newCoords, Float.NaN);
byte[] newColors = new byte[num*clrDim];
float[] newNormals = new float[num*3];
float[] A0 = new float[3];
float[] A1 = new float[3];
float[] B0 = new float[3];
float[] B1 = new float[3];
byte ar0,ag0,ab0,ar1,ag1,ab1,br0,bg0,bb0,br1,bg1,bb1;
byte aa0 = -1;
byte aa1 = -1;
byte ba0 = -1;
byte ba1 = -1;
int numVerts = 0;
for (int k=0; k<ntrajs/2; k++) {
int t = k*2;
Trajectory trajA = trajectories.get(t);
Trajectory trajB = trajectories.get(t+1);
int npairs = Math.min(trajA.npairs, trajB.npairs);
for (int n=0; n<npairs; n++) {
int ia = trajA.indexes[n];
int ib = trajB.indexes[n];
int cia = 2*clrDim*ia/6;
int cib = 2*clrDim*ib/6;
A0[0] = coordinates[ia];
A0[1] = coordinates[ia+1];
A0[2] = coordinates[ia+2];
A1[0] = coordinates[ia+3];
A1[1] = coordinates[ia+4];
A1[2] = coordinates[ia+5];
B0[0] = coordinates[ib];
B0[1] = coordinates[ib+1];
B0[2] = coordinates[ib+2];
B1[0] = coordinates[ib+3];
B1[1] = coordinates[ib+4];
B1[2] = coordinates[ib+5];
if (clrDim == 3) {
ar0 = colors[cia];
ag0 = colors[cia+1];
ab0 = colors[cia+2];
ar1 = colors[cia+3];
ag1 = colors[cia+4];
ab1 = colors[cia+5];
}
else {
ar0 = colors[cia];
ag0 = colors[cia+1];
ab0 = colors[cia+2];
aa0 = colors[cia+3];
ar1 = colors[cia+4];
ag1 = colors[cia+5];
ab1 = colors[cia+6];
aa1 = colors[cia+7];
}
if (clrDim == 3) {
br0 = colors[cib];
bg0 = colors[cib+1];
bb0 = colors[cib+2];
br1 = colors[cib+3];
bg1 = colors[cib+4];
bb1 = colors[cib+5];
}
else {
br0 = colors[cib];
bg0 = colors[cib+1];
bb0 = colors[cib+2];
ba0 = colors[cib+3];
br1 = colors[cib+4];
bg1 = colors[cib+5];
bb1 = colors[cib+6];
ba1 = colors[cib+7];
}
int idx = numVerts*3;
int cidx = numVerts*clrDim;
newCoords[idx] = A0[0];
newCoords[idx+1] = A0[1];
newCoords[idx+2] = A0[2];
newColors[cidx] = ar0;
newColors[cidx+1] = ag0;
newColors[cidx+2] = ab0;
if (clrDim == 4) newColors[cidx+3] = aa0;
numVerts++;
idx = numVerts*3;
cidx = numVerts*clrDim;
newCoords[idx] = B0[0];
newCoords[idx+1] = B0[1];
newCoords[idx+2] = B0[2];
newColors[cidx] = br0;
newColors[cidx+1] = bg0;
newColors[cidx+2] = bb0;
if (clrDim == 4) newColors[cidx+3] = ba0;
numVerts++;
idx = numVerts*3;
cidx = numVerts*clrDim;
newCoords[idx] = B1[0];
newCoords[idx+1] = B1[1];
newCoords[idx+2] = B1[2];
newColors[cidx] = br1;
newColors[cidx+1] = bg1;
newColors[cidx+2] = bb1;
if (clrDim == 4) newColors[cidx+3] = ba1;
numVerts++;
idx = numVerts*3;
cidx = numVerts*clrDim;
newCoords[idx] = B1[0];
newCoords[idx+1] = B1[1];
newCoords[idx+2] = B1[2];
newColors[cidx] = br1;
newColors[cidx+1] = bg1;
newColors[cidx+2] = bb1;
if (clrDim == 4) newColors[cidx+3] = ba1;
numVerts++;
idx = numVerts*3;
cidx = numVerts*clrDim;
newCoords[idx] = A1[0];
newCoords[idx+1] = A1[1];
newCoords[idx+2] = A1[2];
newColors[cidx] = ar1;
newColors[cidx+1] = ag1;
newColors[cidx+2] = ab1;
if (clrDim == 4) newColors[cidx+3] = aa1;
numVerts++;
idx = numVerts*3;
cidx = numVerts*clrDim;
newCoords[idx] = A0[0];
newCoords[idx+1] = A0[1];
newCoords[idx+2] = A0[2];
newColors[cidx] = ar0;
newColors[cidx+1] = ag0;
newColors[cidx+2] = ab0;
if (clrDim == 4) newColors[cidx+3] = aa0;
numVerts++;
}
}
// remove missing:
float[] coords = new float[numVerts*3];
byte[] colors = new byte[numVerts*clrDim];
System.arraycopy(newCoords, 0, coords, 0, coords.length);
System.arraycopy(newColors, 0, colors, 0, colors.length);
array.coordinates = coords;
array.colors = colors;
array.vertexCount = numVerts;
return array;
}
public VisADGeometryArray makePointGeometry() {
int numTrajs = trajectories.size();
float[] allCoords = new float[3*numTrajs];
byte[] allColors = new byte[3*numTrajs];
for (int k=0; k<numTrajs; k++) {
Trajectory traj = trajectories.get(k);
int idx = k*3;
float x = traj.startPts[0];
float y = traj.startPts[1];
float z = traj.startPts[2];
allCoords[idx] = x;
allCoords[idx+1] = y;
allCoords[idx+2] = z;
byte r = traj.startColor[0];
byte g = traj.startColor[1];
byte b = traj.startColor[2];
allColors[idx] = r;
allColors[idx+1] = g;
allColors[idx+2] = b;
}
VisADGeometryArray array = new VisADPointArray();
array.vertexCount = numTrajs;
array.coordinates = allCoords;
array.colors = allColors;
return array;
}
public VisADGeometryArray makeTracerGeometry(ArrayList<float[]> anchors, int direction, float trcrSize, double[] scale, boolean fill) {
int numTrajs = trajectories.size();
VisADGeometryArray array = null;
float[] coords;
byte[] colors;
float[] normals;
int numPts;
int numVerts;
float[] allCoords = new float[3*2*6*numTrajs];
byte[] allColors = new byte[3*2*6*numTrajs];
double barblen = 0.02*trcrSize;
float[] norm = new float[] {0, 0, 1f};
float[] trj_u = new float[3];
for (int k=0; k<numTrajs; k++) {
if (!fill) { // make simple arrow ---------
numPts = 2*4;
numVerts = numPts*1;
coords = new float[3*numVerts];
colors = new byte[3*numVerts];
array = new VisADLineArray();
}
else { // filled arrow head -------------
numPts = 2*6;
numVerts = numPts*1;
coords = new float[3*numVerts];
colors = new byte[3*numVerts];
//normals = new float[3*numVerts];
array = new VisADTriangleArray();
}
Trajectory traj = trajectories.get(k);
trj_u[0] = traj.uVecPath[0];
trj_u[1] = traj.uVecPath[1];
trj_u[2] = traj.uVecPath[2];
float[] endPt = new float[3];
endPt[0] = traj.startPts[0];
endPt[1] = traj.startPts[1];
endPt[2] = traj.startPts[2];
float[] norm_x_trj = new float[] {
norm[1] * trj_u[2] - norm[2] * trj_u[1],
-(norm[0] * trj_u[2] - norm[2] * trj_u[0]),
norm[0] * trj_u[1] - norm[1] * trj_u[0] };
float mag = (float) Math.sqrt(norm_x_trj[0] * norm_x_trj[0] +
norm_x_trj[1] * norm_x_trj[1] +
norm_x_trj[2] * norm_x_trj[2]);
// - normalize vector
norm_x_trj[0] /= mag;
norm_x_trj[1] /= mag;
norm_x_trj[2] /= mag;
float[] norm_x_trj_x_trj = new float[] {
norm_x_trj[1] * trj_u[2] - norm_x_trj[2] * trj_u[1],
-(norm_x_trj[0] * trj_u[2] - norm_x_trj[2] * trj_u[0]),
norm_x_trj[0] * trj_u[1] - norm_x_trj[1] * trj_u[0] };
mag = (float) Math.sqrt(norm_x_trj_x_trj[0] * norm_x_trj_x_trj[0] +
norm_x_trj_x_trj[1] * norm_x_trj_x_trj[1] +
norm_x_trj_x_trj[2] * norm_x_trj_x_trj[2]);
norm_x_trj_x_trj[0] /= mag;
norm_x_trj_x_trj[1] /= mag;
norm_x_trj_x_trj[2] /= mag;
float[] ptOnPath = new float[3];
float len = (float) (barblen*Math.cos(Data.DEGREES_TO_RADIANS*22.0));
ptOnPath[0] = -len*trj_u[0];
ptOnPath[1] = -len*trj_u[1];
ptOnPath[2] = -len*trj_u[2];
ptOnPath[0] += endPt[0];
ptOnPath[1] += endPt[1];
ptOnPath[2] += endPt[2];
float[] barbPtA = new float[3];
float[] barbPtB = new float[3];
float[] barbPtC = new float[3];
float[] barbPtD = new float[3];
len = (float) (barblen*Math.sin(Data.DEGREES_TO_RADIANS*22.0));
barbPtA[0] = len*norm_x_trj[0];
barbPtA[1] = len*norm_x_trj[1];
barbPtA[2] = len*norm_x_trj[2];
barbPtB[0] = -len*norm_x_trj[0];
barbPtB[1] = -len*norm_x_trj[1];
barbPtB[2] = -len*norm_x_trj[2];
barbPtA[0] += ptOnPath[0];
barbPtA[1] += ptOnPath[1];
barbPtA[2] += ptOnPath[2];
barbPtB[0] += ptOnPath[0];
barbPtB[1] += ptOnPath[1];
barbPtB[2] += ptOnPath[2];
len *= scale[0]/scale[2]; // simple adjust for anistropic display scale
barbPtC[0] = len*norm_x_trj_x_trj[0];
barbPtC[1] = len*norm_x_trj_x_trj[1];
barbPtC[2] = len*norm_x_trj_x_trj[2];
barbPtD[0] = -len*norm_x_trj_x_trj[0];
barbPtD[1] = -len*norm_x_trj_x_trj[1];
barbPtD[2] = -len*norm_x_trj_x_trj[2];
barbPtC[0] += ptOnPath[0];
barbPtC[1] += ptOnPath[1];
barbPtC[2] += ptOnPath[2];
barbPtD[0] += ptOnPath[0];
barbPtD[1] += ptOnPath[1];
barbPtD[2] += ptOnPath[2];
int t = 0;
int c = 0;
coords[t] = traj.startPts[0];
coords[t+=1] = traj.startPts[1];
coords[t+=1] = traj.startPts[2];
colors[c] = traj.startColor[0];
colors[c+=1] = traj.startColor[1];
colors[c+=1] = traj.startColor[2];
coords[t+=1] = barbPtA[0];
coords[t+=1] = barbPtA[1];
coords[t+=1] = barbPtA[2];
colors[c+=1] = traj.startColor[0];
colors[c+=1] = traj.startColor[1];
colors[c+=1] = traj.startColor[2];
if (fill) {
coords[t+=1] = ptOnPath[0];
coords[t+=1] = ptOnPath[1];
coords[t+=1] = ptOnPath[2];
colors[c+=1] = traj.startColor[0];
colors[c+=1] = traj.startColor[1];
colors[c+=1] = traj.startColor[2];
}
coords[t+=1] = traj.startPts[0];
coords[t+=1] = traj.startPts[1];
coords[t+=1] = traj.startPts[2];
colors[c+=1] = traj.startColor[0];
colors[c+=1] = traj.startColor[1];
colors[c+=1] = traj.startColor[2];
coords[t+=1] = barbPtB[0];
coords[t+=1] = barbPtB[1];
coords[t+=1] = barbPtB[2];
colors[c+=1] = traj.startColor[0];
colors[c+=1] = traj.startColor[1];
colors[c+=1] = traj.startColor[2];
if (fill) {
coords[t+=1] = ptOnPath[0];
coords[t+=1] = ptOnPath[1];
coords[t+=1] = ptOnPath[2];
colors[c+=1] = traj.startColor[0];
colors[c+=1] = traj.startColor[1];
colors[c+=1] = traj.startColor[2];
}
coords[t+=1] = traj.startPts[0];
coords[t+=1] = traj.startPts[1];
coords[t+=1] = traj.startPts[2];
colors[c+=1] = traj.startColor[0];
colors[c+=1] = traj.startColor[1];
colors[c+=1] = traj.startColor[2];
coords[t+=1] = barbPtC[0];
coords[t+=1] = barbPtC[1];
coords[t+=1] = barbPtC[2];
colors[c+=1] = traj.startColor[0];
colors[c+=1] = traj.startColor[1];
colors[c+=1] = traj.startColor[2];
if (fill) {
coords[t+=1] = ptOnPath[0];
coords[t+=1] = ptOnPath[1];
coords[t+=1] = ptOnPath[2];
colors[c+=1] = traj.startColor[0];
colors[c+=1] = traj.startColor[1];
colors[c+=1] = traj.startColor[2];
}
coords[t+=1] = traj.startPts[0];
coords[t+=1] = traj.startPts[1];
coords[t+=1] = traj.startPts[2];
colors[c+=1] = traj.startColor[0];
colors[c+=1] = traj.startColor[1];
colors[c+=1] = traj.startColor[2];
coords[t+=1] = barbPtD[0];
coords[t+=1] = barbPtD[1];
coords[t+=1] = barbPtD[2];
colors[c+=1] = traj.startColor[0];
colors[c+=1] = traj.startColor[1];
colors[c+=1] = traj.startColor[2];
if (fill) {
coords[t+=1] = ptOnPath[0];
coords[t+=1] = ptOnPath[1];
coords[t+=1] = ptOnPath[2];
colors[c+=1] = traj.startColor[0];
colors[c+=1] = traj.startColor[1];
colors[c+=1] = traj.startColor[2];
}
array.vertexCount = numVerts;
array.coordinates = coords;
array.colors = colors;
float[] anchrPts = new float[] {traj.startPts[0], traj.startPts[1], traj.startPts[2]};
anchors.add(anchrPts);
System.arraycopy(coords, 0, allCoords, k*3*2*6, coords.length);
System.arraycopy(colors, 0, allColors, k*3*2*6, colors.length);
}
VisADTriangleArray allarray = new VisADTriangleArray();
allarray.vertexCount = 2*6*numTrajs;
allarray.coordinates = allCoords;
allarray.colors = allColors;
return allarray;
}
public void initCleanUp(ScalarMap scalarMap, FlowControl flowCntrl, ProjectionControl pCntrl, DisplayImpl display) {
if (!removeListeners.containsKey(scalarMap)) {
removeListeners.put(scalarMap, new ListenForRemove(scalarMap, flowCntrl, pCntrl, display));
}
}
public float[][] getStartPointsFromFile(DataRenderer renderer, ScalarMap altToZ, byte[][] colors) throws VisADException, RemoteException {
String filename = null;
try {
filename = System.getProperty("visad.trajectory.startPointsFile", null);
}
catch (java.lang.SecurityException exc) {
exc.printStackTrace();
}
if (filename == null) {
return null;
}
FieldImpl data = null;
try {
TextAdapter txtAdapter = new TextAdapter(filename);
data = (FieldImpl) txtAdapter.getData();
}
catch (Exception e) {
e.printStackTrace();
return null;
}
int numPts = data.getLength();
ArrayList<float[]> keepPts = new ArrayList();
ArrayList<Float> keepVal = new ArrayList();
for (int k=0; k<numPts; k++) {
RealTuple tup = (RealTuple) data.getSample(k);
double[] vals = tup.getValues();
float[] locVal = new float[3];
locVal[0] = (float) vals[0];
locVal[1] = (float) vals[1];
locVal[2] = (float) vals[2];
keepPts.add(locVal);
//keepVal.add((float)vals[3]);
}
float[][] latlonalt = new float[3][keepPts.size()];
float[] trcrVals = new float[keepPts.size()];
colors[0] = new byte[keepPts.size()];
colors[1] = new byte[keepPts.size()];
colors[2] = new byte[keepPts.size()];
if (colors.length == 4) colors[3] = new byte[keepPts.size()];
for (int k=0; k<keepPts.size(); k++) {
float[] vals = keepPts.get(k);
latlonalt[0][k] = vals[1];
latlonalt[1][k] = vals[0];
latlonalt[2][k] = vals[2];
//float tval = keepVal.get(k);
//trcrVals[k] = tval;
}
// trcr quantity must already be scaled 0 -> 1
float[][] clrTbl = new float[colors.length][256];
BaseColorControl.initTableVis5D(clrTbl);
for (int i=0; i<trcrVals.length; i++) {
float tval = trcrVals[i];
if (tval > 1f) tval = 1f;
int ci = (int) (tval*256f);
colors[0][i] = (byte) (256f * clrTbl[0][ci]);
colors[1][i] = (byte) (256f * clrTbl[1][ci]);
colors[2][i] = (byte) (256f * clrTbl[2][ci]);
if (colors.length == 4) colors[3][i] = (byte) (256f * clrTbl[3][ci]);
}
latlonalt[2] = altToZ.scaleValues(latlonalt[2]);
CoordinateSystem dspCoordSys = renderer.getDisplayCoordinateSystem();
float[][] fltVals = new float[3][latlonalt[0].length];
for (int i=0; i<latlonalt.length; i++) {
System.arraycopy(latlonalt[i], 0, fltVals[i], 0, fltVals[i].length);
}
float[][] xyz = dspCoordSys.toReference(fltVals);
return xyz;
}
}
class ListenForRemove implements ScalarMapListener, DisplayListener {
ScalarMap theMap;
FlowControl flowCntrl;
ProjectionControl pCntrl;
DisplayImpl display;
public ListenForRemove(ScalarMap scalarMap, FlowControl control, ProjectionControl pCntrl, DisplayImpl display) {
theMap = scalarMap;
flowCntrl = control;
this.pCntrl = pCntrl;
this.display = display;
scalarMap.addScalarMapListener(this);
display.addDisplayListener(this);
}
public void displayChanged(DisplayEvent evt) {
int id = evt.getId();
if (id == DisplayEvent.DESTROYED) {
cleanUp();
display.removeDisplayListener(this);
}
}
public void mapChanged(ScalarMapEvent evt) throws VisADException, RemoteException {
}
public void controlChanged(ScalarMapControlEvent evt) throws VisADException, RemoteException {
int id = evt.getId();
if (id == ScalarMapEvent.CONTROL_REMOVED || id == ScalarMapEvent.CONTROL_REPLACED) {
cleanUp();
theMap.removeScalarMapListener(this);
}
}
private void cleanUp() {
ControlListener listener = TrajectoryManager.scaleChangeListeners.get(flowCntrl);
pCntrl.removeControlListener(listener);
TrajectoryManager.scaleChangeListeners.remove(flowCntrl);
TrajectoryManager.removeListeners.remove(theMap);
}
}