Unverified Commit 74433159 authored by tomrink's avatar tomrink Committed by GitHub
Browse files

Merge pull request #148 from tomrink/master

Trajectory enhancements...
parents 2aeadff3 37a5e3d2
......@@ -73,6 +73,8 @@ public class Trajectory {
double[] lastMinDistPt = new double[3];
float last_cellTerrain = Float.NaN;
static float[][] circle;
public Trajectory(TrajectoryManager trajMan, float startX, float startY, float startZ, int[] startCell, float[] cellWeights, byte[] startColor, double initialTime) {
......@@ -463,12 +465,11 @@ public class Trajectory {
int dir = (spatial_values[2][0] < spatial_values[2][lens[0]*lens[1]]) ? 1 : -1;
// get interpolated terrain and parcel height at this grid cell
float cellTerrain = 0;
float parcelHgt = stopPts[2];
float parcelX = stopPts[0];
float parcelY = stopPts[1];
RealTuple xy = new RealTuple(((FunctionType)terrain.getType()).getDomain(), new double[] {parcelX, parcelY});
cellTerrain = (float) ((Real)terrain.evaluate(xy, Data.WEIGHTED_AVERAGE, Data.NO_ERRORS)).getValue();
float cellTerrain = (float) ((Real)terrain.evaluate(xy, Data.WEIGHTED_AVERAGE, Data.NO_ERRORS)).getValue();
float diff = parcelHgt - cellTerrain;
......@@ -476,6 +477,9 @@ public class Trajectory {
if (diff < 0f) {
float zUp = stopPts[2] - diff + 0.0015f;
if (!Float.isNaN(last_cellTerrain) && (Math.abs(last_cellTerrain - cellTerrain) < 0.0005)) {
zUp = startPts[2];
}
float[][] pts3D = new float[3][1];
pts3D[0][0] = stopPts[0];
pts3D[1][0] = stopPts[1];
......@@ -504,6 +508,7 @@ public class Trajectory {
}
}
}
last_cellTerrain = cellTerrain;
}
}
......
......@@ -32,12 +32,14 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import visad.util.CubicInterpolator;
import visad.util.LinearInterpolator;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import visad.data.text.TextAdapter;
import visad.util.Interpolator;
/**
......@@ -67,6 +69,7 @@ public class TrajectoryManager {
public static int[] o_i = new int[] {0, 1, 0, 1};
float[][] startPts;
double[] startTimes;
byte[][] startClrs;
......@@ -75,6 +78,8 @@ public class TrajectoryManager {
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 int TRACER = TrajectoryParams.TRACER;
public static final int TRACER_POINT = TrajectoryParams.TRACER_POINT;
public static final String PPOP_TRAJECTORY_START_POINTS_FILE = "visad.trajectory.startPointsFile";
public static final String PROP_TRAJECTORY_PARAM_FILE_1 = "visad.trajectory.paramFile1";
......@@ -87,8 +92,8 @@ public class TrajectoryManager {
boolean manualIntrpPts;
boolean trajDoIntrp = true;
boolean trajCachingEnabled = false;
//boolean doHysplit = false;
//boolean doRK4 = true;
boolean trcrStreamingEnabled;
boolean saveTracerLocations;
float trcrSize = 1f;
boolean trcrEnabled;
boolean terrainFollowEnabled;
......@@ -112,9 +117,9 @@ public class TrajectoryManager {
float[] intrpU_2;
float[] intrpV_2;
float[] intrpW_2;
CubicInterpolator uInterp;
CubicInterpolator vInterp;
CubicInterpolator wInterp;
Interpolator uInterp;
Interpolator vInterp;
Interpolator wInterp;
float[][] values0;
float[][] values1;
float[][] values2;
......@@ -130,6 +135,13 @@ public class TrajectoryManager {
FlatField terrain = null;
Gridded1DSet anim1DdomainSet;
CoordinateSystem dspCoordSys;
public FieldImpl tracerLocations;
double timeStepScaleFactor;
//- Listener per FlowControl for ProjectionControl events to auto resize tracer geometry.
public static HashMap<FlowControl, ControlListener> scaleChangeListeners = new HashMap<FlowControl, ControlListener>();
......@@ -138,11 +150,13 @@ public class TrajectoryManager {
public TrajectoryManager(DataRenderer renderer, TrajectoryParams trajParams, ArrayList<FlowInfo> flowInfoList, int dataDomainLength, double time) throws VisADException {
this(renderer, trajParams, flowInfoList, dataDomainLength, time, null, null);
this(renderer, trajParams, flowInfoList, dataDomainLength, time, null, null, null);
}
public TrajectoryManager(DataRenderer renderer, TrajectoryParams trajParams, ArrayList<FlowInfo> flowInfoList, int dataDomainLength, double time, ScalarMap altToZ, CoordinateSystem dspCoordSys) throws VisADException {
public TrajectoryManager(DataRenderer renderer, TrajectoryParams trajParams, ArrayList<FlowInfo> flowInfoList, int dataDomainLength, double time, ScalarMap altToZ, CoordinateSystem dspCoordSys, Gridded1DSet anim1DdomainSet) throws VisADException {
this.flowInfoList = flowInfoList;
this.anim1DdomainSet = anim1DdomainSet;
this.dspCoordSys = dspCoordSys;
FlowInfo info = flowInfoList.get(0);
this.dataDomainLength = dataDomainLength;
......@@ -156,10 +170,10 @@ public class TrajectoryManager {
method = trajParams.getMethod();
direction = trajParams.getDirection();
startPts = trajParams.getStartPoints();
trajDoIntrp = trajParams.getDoIntrp();
trcrSize = trajParams.getMarkerSize();
trcrEnabled = trajParams.getMarkerEnabled();
trajCachingEnabled = trajParams.getCachingEnabled();
trcrStreamingEnabled = trajParams.getTracerStreamingEnabled();
terrainFollowEnabled = trajParams.getTerrainFollowing();
trajForm = trajParams.getTrajectoryForm();
cylWidth = trajParams.getCylinderWidth();
......@@ -167,9 +181,8 @@ public class TrajectoryManager {
zStart = trajParams.getZStartIndex();
zSkip = trajParams.getZStartSkip();
startPointType = trajParams.getStartType();
if (!trajDoIntrp) {
numIntrpPts = 1;
}
saveTracerLocations = trajParams.getSaveTracerLocations();
timeStepScaleFactor = trajParams.getTimeStepScaleFactor();
this.altToZ = altToZ;
if (terrainFollowEnabled) {
......@@ -191,6 +204,11 @@ public class TrajectoryManager {
if (terrain != null) {
terrain = terrainToSpatial(terrain, spatialSetTraj, dspCoordSys);
}
if (trajParams.getSaveTracerLocations()) {
FunctionType ftype = new FunctionType(((SetType)anim1DdomainSet.getType()).getDomain(), new FunctionType(RealType.Generic, RealTupleType.LatitudeLongitudeAltitude));
tracerLocations = new FieldImpl(ftype, anim1DdomainSet);
}
byte[][] color_values = info.color_values;
if (info.trajColors != null) color_values = info.trajColors;
......@@ -204,9 +222,12 @@ public class TrajectoryManager {
startClrs = new byte[clrDim][];
double[][] tmp = new double[1][];
if (startPts == null) {
try {
startPts = getStartPointsFromFile(renderer, altToZ, startClrs);
startPts = getStartPointsFromFile(renderer, altToZ, startClrs, tmp);
startTimes = tmp[0];
}
catch (Exception e) {
e.printStackTrace();
......@@ -272,10 +293,24 @@ public class TrajectoryManager {
intrpW_2 = new float[numSpatialPts];
}
uInterp = new CubicInterpolator(trajDoIntrp, numSpatialPts);
vInterp = new CubicInterpolator(trajDoIntrp, numSpatialPts);
wInterp = new CubicInterpolator(trajDoIntrp, numSpatialPts);
if (trajParams.getInterpolationMethod() == TrajectoryParams.InterpolationMethod.Cubic) {
uInterp = new CubicInterpolator(numSpatialPts);
vInterp = new CubicInterpolator(numSpatialPts);
wInterp = new CubicInterpolator(numSpatialPts);
}
else if (trajParams.getInterpolationMethod() == TrajectoryParams.InterpolationMethod.Linear) {
uInterp = new LinearInterpolator(numSpatialPts);
vInterp = new LinearInterpolator(numSpatialPts);
wInterp = new LinearInterpolator(numSpatialPts);
}
else if (trajParams.getInterpolationMethod() == TrajectoryParams.InterpolationMethod.None) {
uInterp = new NoneInterpolator(numSpatialPts);
vInterp = new NoneInterpolator(numSpatialPts);
wInterp = new NoneInterpolator(numSpatialPts);
trajDoIntrp = false;
numIntrpPts = 1;
}
values0 = null;
values1 = null;
values2 = null;
......@@ -285,7 +320,7 @@ public class TrajectoryManager {
/* 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);
makeTrajectories(direction*time, startPts, startTimes, startClrs, spatialSetTraj);
}
public void addPair(float[] startPt, float[] stopPt, byte[] startColor, byte[] stopColor) {
......@@ -377,6 +412,7 @@ public class TrajectoryManager {
}
float timeStep = (float) timeSteps[i]/numIntrpPts;
timeStep *= timeStepScaleFactor;
if (!trajDoIntrp && (method == TrajectoryParams.Method.RK4)) {
timeStep *= 2;
}
......@@ -384,7 +420,15 @@ public class TrajectoryManager {
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);
makeTrajectories(direction*times[i], startPts, startTimes, startClrs, spatialSetTraj);
}
else if (trcrStreamingEnabled) {
java.util.Arrays.fill(markGrid, false);
makeTrajectories(direction*times[i], startPts, null, startClrs, spatialSetTraj);
}
else if (startTimes != null) {
java.util.Arrays.fill(markGrid, false);
makeTrajectories(direction*times[i], startPts, startTimes, startClrs, spatialSetTraj);
}
if (trajForm == POINT) {
......@@ -442,6 +486,24 @@ public class TrajectoryManager {
int numTrajectories = trajectories.size();
reset();
if (saveTracerLocations) {
float[] xyz = new float[3];
if (numTrajectories > 1) {
Integer1DSet set = new Integer1DSet(numTrajectories);
FieldImpl field = new FieldImpl(new FunctionType(RealType.Generic, RealTupleType.LatitudeLongitudeAltitude), set);
for (int j=0; j<set.getLength(); j++) {
float[] startPt = trajectories.get(j).startPts;
float[][] lonlatZ = dspCoordSys.fromReference(new float[][] {{startPt[0]},{startPt[1]},{startPt[2]}});
float lat = lonlatZ[0][0];
float lon = lonlatZ[1][0];
if (lon > 180) lon -= 360;
float alt = altToZ.inverseScaleValues(lonlatZ[2])[0];
field.setSample(j, new RealTuple(RealTupleType.LatitudeLongitudeAltitude, new double[] {lat, lon, alt}));
}
tracerLocations.setSample(i, field);
}
}
for (int ti=0; ti<numIntrpPts; ti++) { // additional points per domain time step
double dst = (x1 - x0)/numIntrpPts;
......@@ -525,6 +587,12 @@ public class TrajectoryManager {
case POINT:
clean();
break;
case TRACER:
clean();
break;
case TRACER_POINT:
clean();
break;
}
if (arrays == null) {
......@@ -534,7 +602,7 @@ public class TrajectoryManager {
return arrays;
}
public void makeTrajectories(double time, float[][] startPts, byte[][] color_values, GriddedSet spatial_set) throws VisADException {
public void makeTrajectories(double time, float[][] startPts, double[] startTimes, byte[][] color_values, GriddedSet spatial_set) throws VisADException {
int num = startPts[0].length;
clrDim = color_values.length;
......@@ -565,8 +633,10 @@ public class TrajectoryManager {
}
if (indices[k] != null) {
Trajectory traj = new Trajectory(this, startX, startY, startZ, indices[k], weights[k], startColor, time);
trajectories.add(traj);
if ((startTimes == null) || (startTimes != null && startTimes[k] <= time)) {
Trajectory traj = new Trajectory(this, startX, startY, startZ, indices[k], weights[k], startColor, time);
trajectories.add(traj);
}
}
}
}
......@@ -2381,15 +2451,20 @@ public class TrajectoryManager {
trajParams.setManualIntrpPts(Boolean.valueOf(propStr.trim()));
}
propStr = prop.getProperty("TrajDoIntrp");
propStr = prop.getProperty("TerrainFollow");
if (propStr != null) {
trajParams.setDoIntrp(Boolean.valueOf(propStr.trim()));
trajParams.setTerrainFollowing(Boolean.valueOf(propStr.trim()));
}
propStr = prop.getProperty("TerrainFollow");
propStr = prop.getProperty("TracerStreaming");
if (propStr != null) {
trajParams.setTerrainFollowing(Boolean.valueOf(propStr.trim()));
}
trajParams.setTracerStreamingEnabled(Boolean.valueOf(propStr.trim()));
}
propStr = prop.getProperty("SaveTracerLocations");
if (propStr != null) {
trajParams.setSaveTracerLocations(Boolean.valueOf(propStr.trim()));
}
propStr = prop.getProperty("NumIntrpPts");
if (propStr != null) {
......@@ -2401,11 +2476,26 @@ public class TrajectoryManager {
trajParams.setTrajRefreshInterval(Double.valueOf(propStr.trim()));
}
propStr = prop.getProperty("TrajVisiblityTimeWindow");
if (propStr != null) {
trajParams.setTrajVisibilityTimeWindow(Double.valueOf(propStr.trim()));
}
propStr = prop.getProperty("TimeStepScaleFactor");
if (propStr != null) {
trajParams.setTimeStepScaleFactor(Double.valueOf(propStr.trim()));
}
propStr = prop.getProperty("StartSkip");
if (propStr != null) {
trajParams.setStartSkip(Integer.valueOf(propStr.trim()));
}
propStr = prop.getProperty("ZStartSkip");
if (propStr != null) {
trajParams.setZStartSkip(Integer.valueOf(propStr.trim()));
}
propStr = prop.getProperty("TrajForm");
if (propStr != null) {
propStr = propStr.trim();
......@@ -2424,6 +2514,12 @@ public class TrajectoryManager {
else if (propStr.equals("POINT")) {
trajParams.setTrajectoryForm(TrajectoryParams.POINT);
}
else if (propStr.equals("TRACER")) {
trajParams.setTrajectoryForm(TrajectoryParams.TRACER);
}
else if (propStr.equals("TRACER_POINT")) {
trajParams.setTrajectoryForm(TrajectoryParams.TRACER_POINT);
}
}
propStr = prop.getProperty("Method");
......@@ -2438,8 +2534,33 @@ public class TrajectoryManager {
else if (propStr.equals("EULER")) {
trajParams.setMethod(TrajectoryParams.Method.Euler);
}
}
}
propStr = prop.getProperty("InterpMethod");
if (propStr != null) {
propStr = propStr.trim();
if (propStr.equals("CUBIC")) {
trajParams.setInterpolationMethod(TrajectoryParams.InterpolationMethod.Cubic);
}
else if (propStr.equals("LINEAR")) {
trajParams.setInterpolationMethod(TrajectoryParams.InterpolationMethod.Linear);
}
else if (propStr.equals("NONE")) {
trajParams.setInterpolationMethod(TrajectoryParams.InterpolationMethod.None);
}
}
propStr = prop.getProperty("Direction");
if (propStr != null) {
propStr = propStr.trim();
if (propStr.equals("FORWARD")) {
trajParams.setDirectionFlag(true);
}
else if (propStr.equals("REVERSE")) {
trajParams.setDirectionFlag(false);
}
}
is.close();
}
}
......@@ -2450,7 +2571,7 @@ public class TrajectoryManager {
return trajParams;
}
public float[][] getStartPointsFromFile(DataRenderer renderer, ScalarMap altToZ, byte[][] colors) throws VisADException, RemoteException {
public float[][] getStartPointsFromFile(DataRenderer renderer, ScalarMap altToZ, byte[][] colors, double[][] times) throws VisADException, RemoteException {
String filename = null;
try {
......@@ -2473,24 +2594,42 @@ public class TrajectoryManager {
return null;
}
RealTupleType rngTupType = (RealTupleType) ((FunctionType)data.getType()).getRange();
int lonIdx = rngTupType.getIndex(RealType.Longitude);
int latIdx = rngTupType.getIndex(RealType.Latitude);
int altIdx = rngTupType.getIndex(RealType.Altitude);
int timeIdx = rngTupType.getIndex(RealType.Time);
int numPts = data.getLength();
ArrayList<float[]> keepPts = new ArrayList();
ArrayList<Float> keepVal = new ArrayList();
ArrayList<Double> keepTime = 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];
locVal[0] = (float) vals[lonIdx];
locVal[1] = (float) vals[latIdx];
locVal[2] = (float) vals[altIdx];
keepPts.add(locVal);
if (vals.length > 3) {
keepVal.add((float)vals[3]);
}
if (timeIdx >= 0) {
keepTime.add(vals[timeIdx]);
}
else {
keepVal.add((float)vals[3]);
}
}
else if (vals.length > 4) {
keepTime.add(vals[timeIdx]);
keepVal.add((float)vals[4]);
}
}
if ((keepVal.size() != 0 ) && keepPts.size() != keepVal.size()) {
throw new VisADException("Trajectory start point file problem: all points must be specified as either lon,lat,alt or lon,lat, alt, val");
if ((keepVal.size() != 0 ) && ((keepPts.size() != keepVal.size()) || (keepPts.size() != keepTime.size()))) {
throw new VisADException("Trajectory start point file problem: all points must be specified as either lon,lat,alt or lon,lat,alt,val or lon,lat,alt,time or lon,lat,alt,time,value");
}
float[][] latlonalt = new float[3][keepPts.size()];
......@@ -2542,7 +2681,17 @@ public class TrajectoryManager {
for (int i=0; i<latlonalt.length; i++) {
System.arraycopy(latlonalt[i], 0, fltVals[i], 0, fltVals[i].length);
}
float[][] xyz = dspCoordSys.toReference(fltVals);
float[][] xyz = dspCoordSys.toReference(fltVals);
int tSize = keepTime.size();
double[] timeVals = null;
if (tSize > 0) {
timeVals = new double[tSize];
}
for (int k=0; k<tSize; k++) {
timeVals[k] = keepTime.get(k);
}
times[0] = timeVals;
return xyz;
}
......@@ -2590,3 +2739,44 @@ class ListenForRemove implements ScalarMapListener, DisplayListener {
}
}
class NoneInterpolator implements Interpolator {
double x0;
double x1;
double x2;
float[] values0;
float[] values1;
float[] values2;
int numSpatialPts;
public NoneInterpolator(int numSpatialPts) {
this.numSpatialPts = numSpatialPts;
}
public void interpolate(double xt, float[] interpValues) {
if (xt == x0) {
System.arraycopy(values0, 0, interpValues, 0, numSpatialPts);
}
else if (xt == x1) {
System.arraycopy(values1, 0, interpValues, 0, numSpatialPts);
}
else if (xt == x2) {
System.arraycopy(values2, 0, interpValues, 0, numSpatialPts);
}
return;
}
public void next(double x0, double x1, double x2, float[] values0, float[] values1, float[] values2) {
this.x0 = x0;
this.x1 = x1;
this.x2 = x2;
this.values0 = values0;
this.values1 = values1;
this.values2 = values2;
return;
}
public void update(boolean[] needed) {
return;
}
}
......@@ -54,11 +54,19 @@ public class TrajectoryParams {
Euler;
}
public static enum InterpolationMethod {
Cubic,
Linear,
None;
}
public static final int LINE = 0;
public static final int RIBBON = 1;
public static final int CYLINDER = 2;
public static final int DEFORM_RIBBON = 3;
public static final int POINT = 4;
public static final int TRACER = 5;
public static final int TRACER_POINT = 6;
double trajVisibilityTimeWindow = 86400.0;
double trajRefreshInterval = 86400.0;
......@@ -67,13 +75,15 @@ public class TrajectoryParams {
SmoothParams smoothParams = SmoothParams.LIGHT;
boolean forward = true;
int direction = 1; //1: forward, -1: backward
boolean doIntrp = true;
//boolean doIntrp = true;
float markerSize = 1f;
boolean markerEnabled = false;
boolean manualIntrpPts = false;
boolean autoSizeMarker = true;
boolean cachingEnabled = true;
boolean terrainFollowEnabled = true;
boolean trcrStreamingEnabled = false;
boolean saveTracerLocations = false;
int trajForm = LINE;
float cylWidth = 0.00014f;
......@@ -89,6 +99,9 @@ public class TrajectoryParams {
FlatField terrain = null;
Method method = Method.HySplit; //Default
InterpolationMethod interpMethod = InterpolationMethod.Cubic;
double timeStepScaleFactor = 1;
public TrajectoryParams() {
}
......@@ -101,7 +114,6 @@ public class TrajectoryParams {
this.smoothParams = params.getSmoothParams();
this.forward = params.getDirectionFlag();
this.direction = params.getDirection();
this.doIntrp = params.getDoIntrp();
this.markerSize = params.getMarkerSize();
this.markerEnabled = params.getMarkerEnabled();
this.manualIntrpPts = params.getManualIntrpPts();
......@@ -117,6 +129,10 @@ public class TrajectoryParams {
this.terrain = params.getTerrain();
this.terrainFollowEnabled = params.getTerrainFollowing();
this.method = params.getMethod();
this.interpMethod = params.getInterpolationMethod();
this.trcrStreamingEnabled = params.getTracerStreamingEnabled();
this.saveTracerLocations = params.getSaveTracerLocations();
this.timeStepScaleFactor = params.getTimeStepScaleFactor();
}
public TrajectoryParams(double trajVisibilityTimeWindow, double trajRefreshInterval, int numIntrpPts, int startSkip, SmoothParams smoothParams) {
......@@ -183,10 +199,6 @@ public class TrajectoryParams {
return forward;
}
public void setDoIntrp(boolean yesno) {
this.doIntrp = yesno;
}
public void setNumIntrpPts(int numIntrpPts) {
this.numIntrpPts = numIntrpPts;
this.manualIntrpPts = true;
......@@ -224,6 +236,10 @@ public class TrajectoryParams {
this.method = method;
}
public void setInterpolationMethod(InterpolationMethod m) {
this.interpMethod = m;
}
public void setCachingEnabled(boolean yesno) {
this.cachingEnabled = yesno;
}
......@@ -288,10 +304,6 @@ public class TrajectoryParams {
return direction;
}