/*
 * 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 flowInfoList;
  
  ArrayList trajectories;
  
  //- Listener per FlowControl for ProjectionControl events to auto resize tracer geometry.
  public static HashMap scaleChangeListeners = new HashMap();
  
  // Listener for ScalarMapControlEvent.CONTROL_REMOVED to remove above classes for garbage collection.
  public static HashMap removeListeners = new HashMap();
  
  
  public TrajectoryManager(DataRenderer renderer, TrajectoryParams trajParams, ArrayList flowInfoList, int dataDomainLength, double time) throws VisADException {
    this(renderer, trajParams, flowInfoList, dataDomainLength, time, null);
  }
  
  public TrajectoryManager(DataRenderer renderer, TrajectoryParams trajParams, ArrayList 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();
      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();
          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 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 newList = new ArrayList();
    Iterator 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 iter = trajectories.iterator();
    ArrayList  removeList = new ArrayList();

    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 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 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 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 keepPts = new ArrayList();
     ArrayList keepVal = new ArrayList();
     for (int k=0; k 1
     
     float[][] clrTbl = new float[colors.length][256];
     BaseColorControl.initTableVis5D(clrTbl);
     
     for (int i=0; i 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 

Ads help maintain this website.