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

Merge pull request #151 from tomrink/master

Doc for GriddedLatLonSet and a few Trajectory improvements.
parents 0b1543a5 bc1f6ce6
......@@ -7,7 +7,6 @@ package visad;
import java.util.ArrayList;
import java.rmi.RemoteException;
import javax.media.j3d.*;
public class FixGeomSizeAppearance implements ControlListener {
......
......@@ -29,8 +29,13 @@ package visad;
import java.io.*;
/**
GriddedLatLonSet represents a finite set of samples of R^2.<P>
*/
*
* @author rink
*
* GriddedLatLonSet represents a finite set of samples with a 2D grid topology on the surface
* of the Earth mapped to R^2: (Longitude, Latitude) or (Latitude, Longitude). This class
* exists primarily to override valueToGrid and gridToValue.
*/
public class GriddedLatLonSet extends Gridded2DSet {
int LengthX, LengthY, TrackLen, latI, lonI;
......@@ -46,7 +51,7 @@ public class GriddedLatLonSet extends Gridded2DSet {
null errors, CoordinateSystem and Units are defaults from type */
public GriddedLatLonSet(MathType type, float[][] samples, int lengthX, int lengthY)
throws VisADException {
this(type, samples, lengthX, lengthY, null, null, null, false, false);
this(type, samples, lengthX, lengthY, null, null, null, false);
}
/** a 2-D set whose topology is a lengthX x lengthY grid;
......@@ -59,23 +64,14 @@ public class GriddedLatLonSet extends Gridded2DSet {
public GriddedLatLonSet(MathType type, float[][] samples, int lengthX, int lengthY,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors) throws VisADException {
this(type, samples, lengthX, lengthY, coord_sys, units, errors,
true, true);
this(type, samples, lengthX, lengthY, coord_sys, units, errors, false);
}
public GriddedLatLonSet(MathType type, float[][] samples, int lengthX, int lengthY,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors, boolean copy)
throws VisADException {
this(type, samples, lengthX, lengthY, coord_sys, units, errors,
copy, true);
}
public GriddedLatLonSet(MathType type, float[][] samples, int lengthX, int lengthY,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors, boolean copy, boolean test)
throws VisADException {
super(type, samples, lengthX, lengthY, coord_sys, units, errors, copy, test);
super(type, samples, lengthX, lengthY, coord_sys, units, errors, copy, false);
LowX = Low[0];
HiX = Hi[0];
......@@ -136,15 +132,17 @@ public class GriddedLatLonSet extends Gridded2DSet {
System.arraycopy(lons, lons0.length, lons1, 0, lons1.length);
System.arraycopy(lats, lats0.length, lats1, 0, lats1.length);
granules[0] = new GriddedLatLonSet(type, new float[][] {lons0, lats0}, LengthX, TrackLen0, coord_sys, units, errors, copy, test);
granules[1] = new GriddedLatLonSet(type, new float[][] {lons1, lats1}, LengthX, TrackLen1, coord_sys, units, errors, copy, test);
granules[0] = new GriddedLatLonSet(type, new float[][] {lons0, lats0}, LengthX, TrackLen0, coord_sys, units, errors, copy);
granules[1] = new GriddedLatLonSet(type, new float[][] {lons1, lats1}, LengthX, TrackLen1, coord_sys, units, errors, copy);
}
}
/** transform an array of non-integer grid coordinates to an array
of values in R^DomainDimension */
/** transform an array of non-integer grid coordinates to an array of values in (Longitude, Latitude).
* Returns nearest neighbor if the cell which contains the grid coordinate straddles
* the dateline or prime meridian.
*/
public float[][] gridToValue(float[][] grid) throws VisADException {
if (grid.length != ManifoldDimension) {
throw new SetException("Gridded2DSet.gridToValue: grid dimension " +
......@@ -258,6 +256,16 @@ public class GriddedLatLonSet extends Gridded2DSet {
return valueToGrid(value, null);
}
/** transform an array of values in R^2 (Longitude, Latitude) to an array
* of non-integer grid coordinates by walking the grid from guess to incoming
* target values by minimizing the angle between vectors from Earth center to the
* their respective Earth coordinates.
* @param value (Longitude, Latitude)
* @param guess Integer grid coordinate. Is replaced by last valid grid located
* by the search. If null, center point of domain is used as guess.
* @return Fractional grid coordinates for incoming values
* @throws visad.VisADException
*/
@Override
public synchronized float[][] valueToGrid(float[][] value, int[] guess) throws VisADException {
......@@ -537,16 +545,16 @@ public class GriddedLatLonSet extends Gridded2DSet {
offGrid = !insideTriangle(gg, CC, LL, DD, tt);
}
else if (gy == 0) {
offGrid = !insideTriangle(gg, LL, UU, RR, tt);
offGrid = !(insideTriangle(gg, CC, UU, LL, tt) || insideTriangle(gg, CC, RR, UU, tt));
}
else if (gy == TrackLen-1) {
offGrid = !insideTriangle(gg, LL, DD, RR, tt);
offGrid = !(insideTriangle(gg, CC, LL, DD, tt) || insideTriangle(gg, CC, DD, RR, tt));
}
else if (gx == 0) {
offGrid = !insideTriangle(gg, UU, RR, DD, tt);
offGrid = !(insideTriangle(gg, CC, UU, RR, tt) || insideTriangle(gg, CC, DD, RR, tt));
}
else if (gx == LengthX-1) {
offGrid = !insideTriangle(gg, UU, LL, DD, tt);
offGrid = !(insideTriangle(gg, CC, UU, LL, tt) || insideTriangle(gg, CC, DD, LL, tt));
}
if (!offGrid) {
......@@ -633,6 +641,13 @@ public class GriddedLatLonSet extends Gridded2DSet {
public static boolean insideTriangle(float[] v0, float[] v1, float[] v2, float[] pt) {
/* Eventhough chance of this happening is small (that the incoming target would fall on a domain point)*/
if ((pt[0] == v0[0] && pt[1] == v0[1] && pt[2] == v0[2]) ||
(pt[0] == v1[0] && pt[1] == v1[1] && pt[2] == v1[2]) ||
(pt[0] == v2[0] && pt[1] == v2[1] && pt[2] == v2[2])) {
return true;
}
float[] triNorm = TrajectoryManager.AxB(new float[] {v1[0]-v0[0], v1[1]-v0[1], v1[2]-v0[2]}, new float[] {v2[0]-v0[0], v2[1]-v0[1], v2[2]-v0[2]}, true);
double[] coeffs = TrajectoryManager.getPlaneCoeffsFromNormalAndPoint(new double[] {(float)triNorm[0], (float)triNorm[1], (float)triNorm[2]}, new double[]{(float)v0[0], (float)v0[1], (float)v0[2]});
......
......@@ -173,20 +173,25 @@ public class Trajectory {
if (terrain != null) {
adjustFlowAtTerrain(terrain, color_values);
}
}
}
addPair(startPts, stopPts, startColor, stopColor);
if (indices[0] == null) {
offGrid = true;
}
else {
addPair(startPts, stopPts, startColor, stopColor);
uVecPath[0] = stopPts[0] - startPts[0];
uVecPath[1] = stopPts[1] - startPts[1];
uVecPath[2] = stopPts[2] - startPts[2];
uVecPath[0] = stopPts[0] - startPts[0];
uVecPath[1] = stopPts[1] - startPts[1];
uVecPath[2] = stopPts[2] - startPts[2];
float mag = (float) Math.sqrt(uVecPath[0]*uVecPath[0] + uVecPath[1]*uVecPath[1] + uVecPath[2]*uVecPath[2]);
uVecPath[0] /= mag;
uVecPath[1] /= mag;
uVecPath[2] /= mag;
update();
float mag = (float) Math.sqrt(uVecPath[0]*uVecPath[0] + uVecPath[1]*uVecPath[1] + uVecPath[2]*uVecPath[2]);
uVecPath[0] /= mag;
uVecPath[1] /= mag;
uVecPath[2] /= mag;
update();
}
}
}
......@@ -400,23 +405,30 @@ public class Trajectory {
}
}
addPair(startPts, stopPts, startColor, stopColor);
if (indices[0] == null) {
offGrid = true;
}
else {
addPair(startPts, stopPts, startColor, stopColor);
uVecPath[0] = stopPts[0] - startPts[0];
uVecPath[1] = stopPts[1] - startPts[1];
uVecPath[2] = stopPts[2] - startPts[2];
uVecPath[0] = stopPts[0] - startPts[0];
uVecPath[1] = stopPts[1] - startPts[1];
uVecPath[2] = stopPts[2] - startPts[2];
float mag = (float) Math.sqrt(uVecPath[0]*uVecPath[0] + uVecPath[1]*uVecPath[1] + uVecPath[2]*uVecPath[2]);
uVecPath[0] /= mag;
uVecPath[1] /= mag;
uVecPath[2] /= mag;
update();
float mag = (float) Math.sqrt(uVecPath[0]*uVecPath[0] + uVecPath[1]*uVecPath[1] + uVecPath[2]*uVecPath[2]);
uVecPath[0] /= mag;
uVecPath[1] /= mag;
uVecPath[2] /= mag;
update();
}
}
}
/*
Add start/stop pair segment to the TrajectoryManager.
*/
private void addPair(float[] startPt, float[] stopPt, byte[] startColor, byte[] stopColor) {
indexes[npairs] = trajMan.getCoordinateCount();
......@@ -435,6 +447,9 @@ public class Trajectory {
}
}
/*
Advance forecast (stop) point location, color and intrp info to the start for the next displacement interval.
*/
private void update() throws VisADException {
startPts[0] = stopPts[0];
......
......@@ -564,6 +564,8 @@ public class TrajectoryManager {
} // inner time loop (time interpolation)
preClean();
values0_last = values0;
values0 = values1;
values1 = values2;
......@@ -680,6 +682,22 @@ public class TrajectoryManager {
}
}
}
/* Remove trajectories from list:
That have less that one complete pair. This may occur with a Trajectory initialized
close to the grid edge and subsequently finds itself offgrid after one step.
*/
public void preClean() {
ArrayList<Trajectory> newList = new ArrayList<Trajectory>();
Iterator<Trajectory> iter = trajectories.iterator();
while (iter.hasNext() ) {
Trajectory traj = iter.next();
if (traj.npairs > 0) {
newList.add(traj);
}
}
trajectories = newList;
}
/* Remove trajectories from list:
(1) That have left the grid (marked offGrid).
......@@ -763,6 +781,7 @@ public class TrajectoryManager {
}
File file = new File(filename);
if (!file.exists()) {
System.out.println("Specified terrain file does not exist: "+filename);
return null;
}
FileInputStream fis = new FileInputStream(file);
......@@ -1821,22 +1840,50 @@ public class TrajectoryManager {
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);
// build cone here. Add to coneArray
if (traj.npairs > 0) { // Keep just in case. PreClean should remove Trajectories with npairs=0
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;
makeCone(traj.last_circleXYZ, vertex, clr0, coneCoords, coneColors, coneNormals, coneIdx);
}
}
// float[] tmpCoords = new float[idx[0]*3];
// float[] tmpNormals = new float[idx[0]*3];
// byte[] tmpColors = new byte[idx[0]*clrDim];
// int[] tmpStrips = new int[strpCnt];
// System.arraycopy(coords, 0, tmpCoords, 0, tmpCoords.length);
// System.arraycopy(normals, 0, tmpNormals, 0, tmpNormals.length);
// System.arraycopy(newColors, 0, tmpColors, 0, tmpColors.length);
// System.arraycopy(strips, 0, tmpStrips, 0, tmpStrips.length);
//
// array.coordinates = tmpCoords;
// array.normals = tmpNormals;
// array.colors = tmpColors;
// array.vertexCount = idx[0];
// array.stripVertexCounts = tmpStrips;
array.coordinates = coords;
array.normals = normals;
array.colors = newColors;
array.vertexCount = coords.length/3;
array.vertexCount = idx[0];
array.stripVertexCounts = strips;
// tmpCoords = new float[coneIdx[0]*3];
// tmpNormals = new float[coneIdx[0]*3];
// tmpColors = new byte[coneIdx[0]*clrDim];
// System.arraycopy(coneCoords, 0, tmpCoords, 0, tmpCoords.length);
// System.arraycopy(coneNormals, 0, tmpNormals, 0, tmpNormals.length);
// System.arraycopy(coneColors, 0, tmpColors, 0, tmpColors.length);
//
// coneArray.coordinates = tmpCoords;
// coneArray.normals = tmpNormals;
// coneArray.colors = tmpColors;
// coneArray.vertexCount = coneIdx[0];
coneArray.coordinates = coneCoords;
coneArray.normals = coneNormals;
coneArray.colors = coneColors;
......@@ -2498,6 +2545,11 @@ public class TrajectoryManager {
trajParams.setZStartSkip(Integer.valueOf(propStr.trim()));
}
propStr = prop.getProperty("ZStartIndex");
if (propStr != null) {
trajParams.setZStartIndex(Integer.valueOf(propStr.trim()));
}
propStr = prop.getProperty("TrajForm");
if (propStr != null) {
propStr = propStr.trim();
......
//
// XTrackScanLatLonSet
//
/*
* 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.
*/
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2018 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;
/**
*
* @author rink
*
* Specialized extension to GriddedLatLonSet for a contiguous collection of spatially overlapping sets
* wherein it's trusted that samples of an individual set are spatially coherent (non-degenerative: no bow-ties).
* Examples are MODIS and VIIRS whose granules are comprised of multiple scans, each with a fixed number of
* detectors, and perpendicular to the polar orbit track, but may overlap when navigated to the Earth's surface.
* The primary purpose of this class is to override valueToGrid.
*
*/
public class XTrackScanLatLonSet extends GriddedLatLonSet {
......@@ -17,22 +45,26 @@ public class XTrackScanLatLonSet extends GriddedLatLonSet {
int lastSetIdx;
public XTrackScanLatLonSet(MathType type, float[][] samples, int lengthX, int lengthY, int linesPerScan) throws VisADException {
super(type, samples, lengthX, lengthY, null, null, null, false, false);
public XTrackScanLatLonSet(MathType type, float[][] samples, int XTrackLen, int TrackLen, int linesPerScan) throws VisADException {
super(type, samples, XTrackLen, TrackLen, null, null, null, false);
if ((TrackLen % linesPerScan) != 0) {
throw new VisADException("There must be an intergral number of scans with detectorsPerScan: "+linesPerScan+" per "
+ "TrackLen: "+TrackLen);
}
this.linesPerScan = linesPerScan;
numOfScans = lengthY/linesPerScan;
numOfScans = TrackLen/linesPerScan;
scanSets = new GriddedLatLonSet[numOfScans];
int scanLen = linesPerScan*lengthX;
float[] scanLonArray = new float[linesPerScan*lengthX];
float[] scanLatArray = new float[linesPerScan*lengthX];
int scanLen = linesPerScan*XTrackLen;
for (int k=0; k<numOfScans; k++) {
float[] scanLonArray = new float[linesPerScan*XTrackLen];
float[] scanLatArray = new float[linesPerScan*XTrackLen];
System.arraycopy(lons, k*scanLen, scanLonArray, 0, scanLen);
System.arraycopy(lats, k*scanLen, scanLatArray, 0, scanLen);
scanSets[k] = new GriddedLatLonSet(RealTupleType.SpatialEarth2DTuple, new float[][] {scanLonArray, scanLatArray}, lengthX, linesPerScan);
scanSets[k] = new GriddedLatLonSet(RealTupleType.SpatialEarth2DTuple, new float[][] {scanLonArray, scanLatArray}, XTrackLen, linesPerScan);
}
}
......@@ -88,6 +120,8 @@ public class XTrackScanLatLonSet extends GriddedLatLonSet {
float[][] lonlat = new float[2][1];
int[] guess_set = new int[2];
guess_set[0] = gx;
guess_set[1] = linesPerScan/2;
for (int i=0; i<length; i++) {
......@@ -119,33 +153,56 @@ public class XTrackScanLatLonSet extends GriddedLatLonSet {
lonlat[latI][0] = targetLat;
float[][] gxgy;
while (lastSetIdx >= 0 && lastSetIdx < numOfScans) {
/* Should never exceed numOfScans */
int cnt = 0;
/* Used to detect infinite stepping back and forth between consecutive scans.
This may happen if the target falls in a gap between two adjacent scans,
for example, near MODIS, VIIRS Nadir. In this situation, NaN is returned but
may consider other options in the future.
*/
int dir = 0;
/* Beginnig with lastSetIdx start walking through the GriddedLatLonSet to find grid
cell which contains the target. If none found, use last test position (must be
on an edge) as guess position for the adjacent scan.
*/
while ((lastSetIdx >= 0 && lastSetIdx < numOfScans) && cnt < numOfScans) {
GriddedLatLonSet scanSet = scanSets[lastSetIdx];
gxgy = scanSet.valueToGrid(lonlat, guess_set);
if (gxgy[0][0] == Float.NaN || gxgy[1][0] == Float.NaN) {
int gx_set = scanSet.lgxy[0];
int gy_set = scanSet.lgxy[1];
if (Float.isNaN(gxgy[0][0]) || Float.isNaN(gxgy[1][0])) {
int gx_set = guess_set[0];
int gy_set = guess_set[1];
if (gy_set == 0) {
lastSetIdx -= 1;
guess_set[0] = gx_set;
guess_set[1] = linesPerScan-1;
if (dir == 1) {
break;
}
dir = -1;
}
else if (gy_set == linesPerScan-1) {
lastSetIdx += 1;
guess_set[0] = gx_set;
guess_set[1] = 0;
if (dir == -1) {
break;
}
dir = 1;
}
else if (gx_set == 0 || gx_set == LengthX-1) {
break;
}
cnt++;
}
else {
grid[0][i] = gxgy[0][0];
grid[1][i] = (lastSetIdx-1)*linesPerScan + gxgy[1][0];
grid[1][i] = lastSetIdx*linesPerScan + gxgy[1][0];
lgxy[0] = scanSet.lgxy[0];
lgxy[1] = scanSet.lgxy[1] + (lastSetIdx-1)*linesPerScan;
lgxy[1] = scanSet.lgxy[1] + lastSetIdx*linesPerScan;
break;
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment