//
// Gridded2DDoubleSet.java
//
/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad;
/**
Gridded2DDoubleSet is a Gridded2DSet with double-precision samples.<P>
*/
public class Gridded2DDoubleSet extends Gridded2DSet
implements GriddedDoubleSet {
double[] Low = new double[2];
double[] Hi = new double[2];
double LowX, HiX, LowY, HiY;
double[][] Samples;
// Overridden Gridded2DSet constructors (float[][])
/** a 2-D set whose topology is a lengthX x lengthY grid, with
null errors, CoordinateSystem and Units are defaults from type */
public Gridded2DDoubleSet(MathType type, float[][] samples, int lengthX, int lengthY)
throws VisADException {
this(type, Set.floatToDouble(samples), lengthX, lengthY, null, null, null, true);
}
/** a 2-D set whose topology is a lengthX x lengthY grid;
samples array is organized float[2][number_of_samples] where
lengthX * lengthY = number_of_samples; samples must form a
non-degenerate 2-D grid (no bow-tie-shaped grid boxes); the
X component increases fastest in the second index of samples;
coordinate_system and units must be compatible with defaults
for type, or may be null; errors may be null */
public Gridded2DDoubleSet(MathType type, float[][] samples, int lengthX, int lengthY,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors) throws VisADException {
this(type, Set.floatToDouble(samples), lengthX, lengthY, coord_sys,
units, errors, true);
}
Gridded2DDoubleSet(MathType type, float[][] samples, int lengthX, int lengthY,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors, boolean copy)
throws VisADException {
this(type, Set.floatToDouble(samples), lengthX, lengthY, coord_sys,
units, errors, copy);
}
/** a 2-D set with manifold dimension = 1, with null errors,
CoordinateSystem and Units are defaults from type */
public Gridded2DDoubleSet(MathType type, float[][] samples, int lengthX)
throws VisADException {
this(type, Set.floatToDouble(samples), lengthX, null, null, null, true);
}
/** a 2-D set with manifold dimension = 1; samples array is
organized float[2][number_of_samples] where lengthX =
number_of_samples; no geometric constraint on samples;
coordinate_system and units must be compatible with defaults
for type, or may be null; errors may be null */
public Gridded2DDoubleSet(MathType type, float[][] samples, int lengthX,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors) throws VisADException {
this(type, Set.floatToDouble(samples), lengthX, coord_sys, units, errors, true);
}
public Gridded2DDoubleSet(MathType type, float[][] samples, int lengthX,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors, boolean copy)
throws VisADException {
this(type, Set.floatToDouble(samples), lengthX, coord_sys, units, errors, copy);
}
// Corresponding Gridded2DDoubleSet constructors (double[][])
/** a 2-D set whose topology is a lengthX x lengthY grid, with
null errors, CoordinateSystem and Units are defaults from type */
public Gridded2DDoubleSet(MathType type, double[][] samples, int lengthX, int lengthY)
throws VisADException {
this(type, samples, lengthX, lengthY, null, null, null, true);
}
/** a 2-D set whose topology is a lengthX x lengthY grid;
samples array is organized double[2][number_of_samples] where
lengthX * lengthY = number_of_samples; samples must form a
non-degenerate 2-D grid (no bow-tie-shaped grid boxes); the
X component increases fastest in the second index of samples;
coordinate_system and units must be compatible with defaults
for type, or may be null; errors may be null */
public Gridded2DDoubleSet(MathType type, double[][] samples, int lengthX, int lengthY,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors) throws VisADException {
this(type, samples, lengthX, lengthY, coord_sys, units, errors, true);
}
public Gridded2DDoubleSet(MathType type, double[][] 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 Gridded2DDoubleSet(MathType type, double[][] samples, int lengthX,
int lengthY, CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors, boolean copy, boolean test)
throws VisADException {
super(type, null, lengthX, lengthY, coord_sys, units, errors, copy);
if (samples == null) {
throw new SetException("Gridded2DDoubleSet: samples are null");
}
init_doubles(samples, copy);
LowX = Low[0];
HiX = Hi[0];
LengthX = Lengths[0];
LowY = Low[1];
HiY = Hi[1];
LengthY = Lengths[1];
if (Samples != null && Lengths[0] > 1 && Lengths[1] > 1) {
for (int i=0; i<Length; i++) {
if (Samples[0][i] != Samples[0][i]) {
throw new SetException(
"Gridded2DDoubleSet: samples values may not be missing");
}
}
// Samples consistency test
/* CICERO
Pos = ( (Samples[0][1]-Samples[0][0])
*(Samples[1][LengthX+1]-Samples[1][1])
- (Samples[1][1]-Samples[1][0])
*(Samples[0][LengthX+1]-Samples[0][1]) > 0);
*/
// CICERO
double xpos = (Samples[0][1]-Samples[0][0])
*(Samples[1][LengthX+1]-Samples[1][1])
- (Samples[1][1]-Samples[1][0])
*(Samples[0][LengthX+1]-Samples[0][1]);
Pos = (xpos > 0);
if (test) {
// CICERO
if (xpos == 0) {
throw new SetException(
"Gridded2DSet: samples do not form a valid grid");
}
double[] v00 = new double[2];
double[] v10 = new double[2];
double[] v01 = new double[2];
double[] v11 = new double[2];
for (int j=0; j<LengthY-1; j++) {
for (int i=0; i<LengthX-1; i++) {
for (int v=0; v<2; v++) {
v00[v] = Samples[v][j*LengthX+i];
v10[v] = Samples[v][j*LengthX+i+1];
v01[v] = Samples[v][(j+1)*LengthX+i];
v11[v] = Samples[v][(j+1)*LengthX+i+1];
}
/* CICERO
if ( ( (v10[0]-v00[0])*(v11[1]-v10[1])
- (v10[1]-v00[1])*(v11[0]-v10[0]) > 0 != Pos)
|| ( (v11[0]-v10[0])*(v01[1]-v11[1])
- (v11[1]-v10[1])*(v01[0]-v11[0]) > 0 != Pos)
|| ( (v01[0]-v11[0])*(v00[1]-v01[1])
- (v01[1]-v11[1])*(v00[0]-v01[0]) > 0 != Pos)
|| ( (v00[0]-v01[0])*(v10[1]-v00[1])
- (v00[1]-v01[1])*(v10[0]-v00[0]) > 0 != Pos) ) {
*/
// CICERO
double w1 = ( (v10[0]-v00[0])*(v11[1]-v10[1])
- (v10[1]-v00[1])*(v11[0]-v10[0]) );
double w2 = ( (v11[0]-v10[0])*(v01[1]-v11[1])
- (v11[1]-v10[1])*(v01[0]-v11[0]) );
double w3 = ( (v01[0]-v11[0])*(v00[1]-v01[1])
- (v01[1]-v11[1])*(v00[0]-v01[0]) );
double w4 = ( (v00[0]-v01[0])*(v10[1]-v00[1])
- (v00[1]-v01[1])*(v10[0]-v00[0]) );
if ((w1 > 0 != Pos) || w1 == 0 ||
(w2 > 0 != Pos) || w2 == 0 ||
(w3 > 0 != Pos) || w3 == 0 ||
(w4 > 0 != Pos) || w4 == 0) {
throw new SetException(
"Gridded2DDoubleSet: samples do not form a valid grid ("+i+","+j+")");
}
}
}
} // end if (test)
}
}
/** a 2-D set with manifold dimension = 1, with null errors,
CoordinateSystem and Units are defaults from type */
public Gridded2DDoubleSet(MathType type, double[][] samples, int lengthX)
throws VisADException {
this(type, samples, lengthX, null, null, null);
}
/** a 2-D set with manifold dimension = 1; samples array is
organized double[2][number_of_samples] where lengthX =
number_of_samples; no geometric constraint on samples;
coordinate_system and units must be compatible with defaults
for type, or may be null; errors may be null */
public Gridded2DDoubleSet(MathType type, double[][] samples, int lengthX,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors) throws VisADException {
this(type, samples, lengthX, coord_sys, units, errors, true);
}
public Gridded2DDoubleSet(MathType type, double[][] samples, int lengthX,
CoordinateSystem coord_sys, Unit[] units,
ErrorEstimate[] errors, boolean copy)
throws VisADException {
super(type, null, lengthX, coord_sys, units, errors, copy);
if (samples == null) {
throw new SetException("Gridded2DDoubleSet: samples are null");
}
init_doubles(samples, copy);
LowX = Low[0];
HiX = Hi[0];
LengthX = Lengths[0];
LowY = Low[1];
HiY = Hi[1];
// no Samples consistency test
}
//END
// Overridden Gridded2DSet methods (float[][])
public float[][] getSamples() throws VisADException {
return getSamples(true);
}
public float[][] getSamples(boolean copy) throws VisADException {
return Set.doubleToFloat(Samples);
}
/** convert an array of 1-D indices to an array of values in R^DomainDimension */
public float[][] indexToValue(int[] index) throws VisADException {
return Set.doubleToFloat(indexToDouble(index));
}
/** convert an array of values in R^DomainDimension to an array of 1-D indices */
public int[] valueToIndex(float[][] value) throws VisADException {
return doubleToIndex(Set.floatToDouble(value));
}
/** transform an array of non-integer grid coordinates to an array
of values in R^DomainDimension */
public float[][] gridToValue(float[][] grid) throws VisADException {
return Set.doubleToFloat(gridToDouble(Set.floatToDouble(grid)));
}
/** transform an array of values in R^DomainDimension to an array
of non-integer grid coordinates */
public float[][] valueToGrid(float[][] value) throws VisADException {
return Set.doubleToFloat(doubleToGrid(Set.floatToDouble(value)));
}
/** for each of an array of values in R^DomainDimension, compute an array
of 1-D indices and an array of weights, to be used for interpolation;
indices[i] and weights[i] are null if i-th value is outside grid
(i.e., if no interpolation is possible) */
public void valueToInterp(float[][] value, int[][] indices,
float[][] weights) throws VisADException
{
int len = weights.length;
double[][] w = new double[len][];
doubleToInterp(Set.floatToDouble(value), indices, w);
for (int i=0; i<len; i++) {
if (w[i] != null) {
weights[i] = new float[w[i].length];
for (int j=0; j<w[i].length; j++) {
weights[i][j] = (float) w[i][j];
}
}
}
}
// Corresponding Gridded2DDoubleSet methods (double[][])
public double[][] getDoubles() throws VisADException {
return getDoubles(true);
}
public double[][] getDoubles(boolean copy) throws VisADException {
return copy ? Set.copyDoubles(Samples) : Samples;
}
/** convert an array of 1-D indices to an array of values in
R^DomainDimension */
public double[][] indexToDouble(int[] index) throws VisADException {
int length = index.length;
if (Samples == null) {
// not used - over-ridden by Linear2DSet.indexToValue
int indexX, indexY;
double[][] grid = new double[ManifoldDimension][length];
for (int i=0; i<length; i++) {
if (0 <= index[i] && index[i] < Length) {
indexX = index[i] % LengthX;
indexY = index[i] / LengthX;
}
else {
indexX = -1;
indexY = -1;
}
grid[0][i] = indexX;
grid[1][i] = indexY;
}
return gridToDouble(grid);
}
else {
double[][] values = new double[2][length];
for (int i=0; i<length; i++) {
if (0 <= index[i] && index[i] < Length) {
values[0][i] = Samples[0][index[i]];
values[1][i] = Samples[1][index[i]];
}
else {
values[0][i] = Double.NaN;
values[1][i] = Double.NaN;
}
}
return values;
}
}
/** convert an array of values in R^DomainDimension to an array of 1-D indices */
public int[] doubleToIndex(double[][] value) throws VisADException {
if (value.length != DomainDimension) {
throw new SetException("Gridded2DDoubleSet.doubleToIndex: value dimension " +
value.length + " not equal to Domain dimension " +
DomainDimension);
}
int length = value[0].length;
int[] index = new int[length];
double[][] grid = doubleToGrid(value);
double[] grid0 = grid[0];
double[] grid1 = grid[1];
double g0, g1;
for (int i=0; i<length; i++) {
g0 = grid0[i];
g1 = grid1[i];
/* WLH 24 Oct 97
index[i] = (Double.isNaN(g0) || Double.isNaN(g1)) ? -1 :
*/
// test for missing
index[i] = (g0 != g0 || g1 != g1) ? -1 :
((int) (g0 + 0.5)) + LengthX * ((int) (g1 + 0.5));
}
return index;
}
/** transform an array of non-integer grid coordinates to an array
of values in R^DomainDimension */
public double[][] gridToDouble(double[][] grid) throws VisADException {
if (grid.length != ManifoldDimension) {
throw new SetException("Gridded2DDoubleSet.gridToDouble: bad dimension");
}
if (ManifoldDimension < 2) {
throw new SetException("Gridded2DDoubleSet.gridToDouble: ManifoldDimension " +
"must be 2");
}
if (Length > 1 && (Lengths[0] < 2 || Lengths[1] < 2)) {
throw new SetException("Gridded2DDoubleSet.gridToDouble: requires all grid " +
"dimensions to be > 1");
}
// avoid any ArrayOutOfBounds exceptions by taking the shortest length
int length = Math.min(grid[0].length, grid[1].length);
double[][] value = new double[2][length];
for (int i=0; i<length; i++) {
// let gx and gy by the current grid values
double gx = grid[0][i];
double gy = grid[1][i];
if ( (gx < -0.5) || (gy < -0.5) ||
(gx > LengthX-0.5) || (gy > LengthY-0.5) ) {
value[0][i] = value[1][i] = Double.NaN;
} else if (Length == 1) {
value[0][i] = Samples[0][0];
value[1][i] = Samples[1][0];
} else {
// calculate closest integer variables
int igx = (int) gx;
int igy = (int) gy;
if (igx < 0) igx = 0;
if (igx > LengthX-2) igx = LengthX-2;
if (igy < 0) igy = 0;
if (igy > LengthY-2) igy = LengthY-2;
// set up conversion to 1D Samples array
int[][] s = { {LengthX*igy+igx, // (0, 0)
LengthX*(igy+1)+igx}, // (0, 1)
{LengthX*igy+igx+1, // (1, 0)
LengthX*(igy+1)+igx+1} }; // (1, 1)
if (gx+gy-igx-igy-1 <= 0) {
// point is in LOWER triangle
for (int j=0; j<2; j++) {
value[j][i] = Samples[j][s[0][0]]
+ (gx-igx)*(Samples[j][s[1][0]]-Samples[j][s[0][0]])
+ (gy-igy)*(Samples[j][s[0][1]]-Samples[j][s[0][0]]);
}
}
else {
// point is in UPPER triangle
for (int j=0; j<2; j++) {
value[j][i] = Samples[j][s[1][1]]
+ (1+igx-gx)*(Samples[j][s[0][1]]-Samples[j][s[1][1]])
+ (1+igy-gy)*(Samples[j][s[1][0]]-Samples[j][s[1][1]]);
}
}
}
}
return value;
}
// WLH 6 Dec 2001
//private int gx = -1;
//private int gy = -1;
/** transform an array of values in R^DomainDimension to an array
of non-integer grid coordinates */
public double[][] doubleToGrid(double[][] value) throws VisADException {
if (value.length < DomainDimension) {
throw new SetException("Gridded2DDoubleSet.doubleToGrid: bad dimension");
}
if (ManifoldDimension < 2) {
throw new SetException("Gridded2DDoubleSet.doubleToGrid: ManifoldDimension " +
"must be 2");
}
if (Length > 1 && (Lengths[0] < 2 || Lengths[1] < 2)) {
throw new SetException("Gridded2DDoubleSet.doubleToGrid: requires all grid " +
"dimensions to be > 1");
}
int length = Math.min(value[0].length, value[1].length);
double[][] grid = new double[ManifoldDimension][length];
// (gx, gy) is the current grid box guess
int gx = (LengthX-1)/2;
int gy = (LengthY-1)/2;
/* WLH 6 Dec 2001
// use value from last call as first guess, if reasonable
if (gx < 0 || gx >= LengthX || gy < 0 || gy >= LengthY) {
gx = (LengthX-1)/2;
gy = (LengthY-1)/2;
}
*/
boolean lowertri = true;
for (int i=0; i<length; i++) {
// grid box guess starts at previous box unless there was no solution
/* WLH 24 Oct 97
if ( (i != 0) && (Double.isNaN(grid[0][i-1])) )
*/
if (Length == 1) {
if (Double.isNaN(value[0][i]) || Double.isNaN(value[1][i])) {
grid[0][i] = grid[1][i] = Double.NaN;
} else {
grid[0][i] = 0;
grid[1][i] = 0;
}
continue;
}
// test for missing
if ( (i != 0) && grid[0][i-1] != grid[0][i-1] ) {
gx = (LengthX-1)/2;
gy = (LengthY-1)/2;
}
// if the loop doesn't find the answer, the result should be NaN
grid[0][i] = grid[1][i] = Double.NaN;
for (int itnum=0; itnum<2*(LengthX+LengthY); itnum++) {
// define the four vertices of the current grid box
double[] v0 = {Samples[0][gy*LengthX+gx],
Samples[1][gy*LengthX+gx]};
double[] v1 = {Samples[0][gy*LengthX+gx+1],
Samples[1][gy*LengthX+gx+1]};
double[] v2 = {Samples[0][(gy+1)*LengthX+gx],
Samples[1][(gy+1)*LengthX+gx]};
double[] v3 = {Samples[0][(gy+1)*LengthX+gx+1],
Samples[1][(gy+1)*LengthX+gx+1]};
// Both cases use diagonal D-B and point distances P-B and P-D
double[] bd = {v2[0]-v1[0], v2[1]-v1[1]};
double[] bp = {value[0][i]-v1[0], value[1][i]-v1[1]};
double[] dp = {value[0][i]-v2[0], value[1][i]-v2[1]};
// check the LOWER triangle of the grid box
if (lowertri) {
double[] ab = {v1[0]-v0[0], v1[1]-v0[1]};
double[] da = {v0[0]-v2[0], v0[1]-v2[1]};
double[] ap = {value[0][i]-v0[0], value[1][i]-v0[1]};
double tval1 = ab[0]*ap[1]-ab[1]*ap[0];
double tval2 = bd[0]*bp[1]-bd[1]*bp[0];
double tval3 = da[0]*dp[1]-da[1]*dp[0];
boolean test1 = (tval1 == 0) || ((tval1 > 0) == Pos);
boolean test2 = (tval2 == 0) || ((tval2 > 0) == Pos);
boolean test3 = (tval3 == 0) || ((tval3 > 0) == Pos);
int ogx = gx;
int ogy = gy;
if (!test1 && !test2) { // Go UP & RIGHT
gx++;
gy--;
}
else if (!test2 && !test3) { // Go DOWN & LEFT
gx--;
gy++;
}
else if (!test1 && !test3) { // Go UP & LEFT
gx--;
gy--;
}
else if (!test1) { // Go UP
gy--;
}
else if (!test3) { // Go LEFT
gx--;
}
// Snap guesses back into the grid
if (gx < 0) gx = 0;
if (gx > LengthX-2) gx = LengthX-2;
if (gy < 0) gy = 0;
if (gy > LengthY-2) gy = LengthY-2;
if ( (gx == ogx) && (gy == ogy) && (test2) ) {
// Found correct grid triangle
// Solve the point with the reverse interpolation
grid[0][i] = ((value[0][i]-v0[0])*(v2[1]-v0[1])
+ (v0[1]-value[1][i])*(v2[0]-v0[0]))
/ ((v1[0]-v0[0])*(v2[1]-v0[1])
+ (v0[1]-v1[1])*(v2[0]-v0[0])) + gx;
grid[1][i] = ((value[0][i]-v0[0])*(v1[1]-v0[1])
+ (v0[1]-value[1][i])*(v1[0]-v0[0]))
/ ((v2[0]-v0[0])*(v1[1]-v0[1])
+ (v0[1]-v2[1])*(v1[0]-v0[0])) + gy;
break;
}
else {
lowertri = false;
}
}
// check the UPPER triangle of the grid box
else {
double[] bc = {v3[0]-v1[0], v3[1]-v1[1]};
double[] cd = {v2[0]-v3[0], v2[1]-v3[1]};
double[] cp = {value[0][i]-v3[0], value[1][i]-v3[1]};
double tval1 = bc[0]*bp[1]-bc[1]*bp[0];
double tval2 = cd[0]*cp[1]-cd[1]*cp[0];
double tval3 = bd[0]*dp[1]-bd[1]*dp[0];
boolean test1 = (tval1 == 0) || ((tval1 > 0) == Pos);
boolean test2 = (tval2 == 0) || ((tval2 > 0) == Pos);
boolean test3 = (tval3 == 0) || ((tval3 < 0) == Pos);
int ogx = gx;
int ogy = gy;
if (!test1 && !test3) { // Go UP & RIGHT
gx++;
gy--;
}
else if (!test2 && !test3) { // Go DOWN & LEFT
gx--;
gy++;
}
else if (!test1 && !test2) { // Go DOWN & RIGHT
gx++;
gy++;
}
else if (!test1) { // Go RIGHT
gx++;
}
else if (!test2) { // Go DOWN
gy++;
}
// Snap guesses back into the grid
if (gx < 0) gx = 0;
if (gx > LengthX-2) gx = LengthX-2;
if (gy < 0) gy = 0;
if (gy > LengthY-2) gy = LengthY-2;
if ( (gx == ogx) && (gy == ogy) && (test3) ) {
// Found correct grid triangle
// Solve the point with the reverse interpolation
grid[0][i] = ((v3[0]-value[0][i])*(v1[1]-v3[1])
+ (value[1][i]-v3[1])*(v1[0]-v3[0]))
/ ((v2[0]-v3[0])*(v1[1]-v3[1])
- (v2[1]-v3[1])*(v1[0]-v3[0])) + gx + 1;
grid[1][i] = ((v2[1]-v3[1])*(v3[0]-value[0][i])
+ (v2[0]-v3[0])*(value[1][i]-v3[1]))
/ ((v1[0]-v3[0])*(v2[1]-v3[1])
- (v2[0]-v3[0])*(v1[1]-v3[1])) + gy + 1;
break;
}
else {
lowertri = true;
}
}
}
if ( (grid[0][i] >= LengthX-0.5) || (grid[1][i] >= LengthY-0.5)
|| (grid[0][i] <= -0.5) || (grid[1][i] <= -0.5) ) {
grid[0][i] = grid[1][i] = Double.NaN;
}
}
return grid;
}
/** for each of an array of values in R^DomainDimension, compute an array
of 1-D indices and an array of weights, to be used for interpolation;
indices[i] and weights[i] are null if i-th value is outside grid
(i.e., if no interpolation is possible) */
public void doubleToInterp(double[][] value, int[][] indices,
double[][] weights) throws VisADException
{
if (value.length != DomainDimension) {
throw new SetException("Gridded2DDoubleSet.doubleToInterp: value dimension " +
value.length + " not equal to Domain dimension " +
DomainDimension);
}
int length = value[0].length; // number of values
if (indices.length != length) {
throw new SetException("Gridded2DDoubleSet.valueToInterp: indices length " +
indices.length +
" doesn't match value[0] length " +
value[0].length);
}
if (weights.length != length) {
throw new SetException("Gridded2DDoubleSet.valueToInterp: weights length " +
weights.length +
" doesn't match value[0] length " +
value[0].length);
}
// convert value array to grid coord array
double[][] grid = doubleToGrid(value);
int i, j, k; // loop indices
int lis; // temporary length of is & cs
int length_is; // final length of is & cs, varies by i
int isoff; // offset along one grid dimension
double a, b; // weights along one grid dimension; a + b = 1.0
int[] is; // array of indices, becomes part of indices
double[] cs; // array of coefficients, become part of weights
int base; // base index, as would be returned by valueToIndex
int[] l = new int[ManifoldDimension]; // integer 'factors' of base
// fractions with l; -0.5 <= c <= 0.5
double[] c = new double[ManifoldDimension];
// array of index offsets by grid dimension
int[] off = new int[ManifoldDimension];
off[0] = 1;
for (j=1; j<ManifoldDimension; j++) off[j] = off[j-1] * Lengths[j-1];
for (i=0; i<length; i++) {
// compute length_is, base, l & c
length_is = 1;
if (Double.isNaN(grid[ManifoldDimension-1][i])) {
base = -1;
}
else {
l[ManifoldDimension-1] = (int) (grid[ManifoldDimension-1][i] + 0.5);
// WLH 23 Dec 99
if (l[ManifoldDimension-1] == Lengths[ManifoldDimension-1]) {
l[ManifoldDimension-1]--;
}
c[ManifoldDimension-1] = grid[ManifoldDimension-1][i] -
((double) l[ManifoldDimension-1]);
if (!((l[ManifoldDimension-1] == 0 && c[ManifoldDimension-1] <= 0.0) ||
(l[ManifoldDimension-1] == Lengths[ManifoldDimension-1] - 1 &&
c[ManifoldDimension-1] >= 0.0))) {
// only interp along ManifoldDimension-1
// if between two valid grid coords
length_is *= 2;
}
base = l[ManifoldDimension-1];
}
for (j=ManifoldDimension-2; j>=0 && base>=0; j--) {
if (Double.isNaN(grid[j][i])) {
base = -1;
}
else {
l[j] = (int) (grid[j][i] + 0.5);
if (l[j] == Lengths[j]) l[j]--; // WLH 23 Dec 99
c[j] = grid[j][i] - ((double) l[j]);
if (!((l[j] == 0 && c[j] <= 0.0) ||
(l[j] == Lengths[j] - 1 && c[j] >= 0.0))) {
// only interp along dimension j if between two valid grid coords
length_is *= 2;
}
base = l[j] + Lengths[j] * base;
}
}
if (base < 0) {
// value is out of grid so return null
is = null;
cs = null;
}
else {
// create is & cs of proper length, and init first element
is = new int[length_is];
cs = new double[length_is];
is[0] = base;
cs[0] = 1.0f;
lis = 1;
for (j=0; j<ManifoldDimension; j++) {
if (!((l[j] == 0 && c[j] <= 0.0) ||
(l[j] == Lengths[j] - 1 && c[j] >= 0.0))) {
// only interp along dimension j if between two valid grid coords
if (c[j] >= 0.0) {
// grid coord above base
isoff = off[j];
a = 1.0f - c[j];
b = c[j];
}
else {
// grid coord below base
isoff = -off[j];
a = 1.0f + c[j];
b = -c[j];
}
// double is & cs; adjust new offsets; split weights
for (k=0; k<lis; k++) {
is[k+lis] = is[k] + isoff;
cs[k+lis] = cs[k] * b;
cs[k] *= a;
}
lis *= 2;
}
}
}
indices[i] = is;
weights[i] = cs;
}
}
// Miscellaneous Set methods that must be overridden
// (this code is duplicated throughout all *DoubleSet classes)
void init_doubles(double[][] samples, boolean copy)
throws VisADException {
if (samples.length != DomainDimension) {
throw new SetException("Gridded2DDoubleSet.init_doubles: samples " +
" dimension " + samples.length +
" not equal to domain dimension " +
DomainDimension);
}
if (Length == 0) {
// Length set in init_lengths, but not called for IrregularSet
Length = samples[0].length;
}
else {
if (Length != samples[0].length) {
throw new SetException("Gridded2DDoubleSet.init_doubles: " +
"samples[0] length " + samples[0].length +
" doesn't match expected length " + Length);
}
}
// MEM
if (copy) {
Samples = new double[DomainDimension][Length];
}
else {
Samples = samples;
}
for (int j=0; j<DomainDimension; j++) {
if (samples[j].length != Length) {
throw new SetException("Gridded2DDoubleSet.init_doubles: " +
"samples[" + j + "] length " +
samples[0].length +
" doesn't match expected length " + Length);
}
double[] samplesJ = samples[j];
double[] SamplesJ = Samples[j];
if (copy) {
System.arraycopy(samplesJ, 0, SamplesJ, 0, Length);
}
Low[j] = Double.POSITIVE_INFINITY;
Hi[j] = Double.NEGATIVE_INFINITY;
double sum = 0.0f;
for (int i=0; i<Length; i++) {
if (SamplesJ[i] == SamplesJ[i] && !Double.isInfinite(SamplesJ[i])) {
if (SamplesJ[i] < Low[j]) Low[j] = SamplesJ[i];
if (SamplesJ[i] > Hi[j]) Hi[j] = SamplesJ[i];
}
else {
SamplesJ[i] = Double.NaN;
}
sum += SamplesJ[i];
}
if (SetErrors[j] != null ) {
SetErrors[j] =
new ErrorEstimate(SetErrors[j].getErrorValue(), sum / Length,
Length, SetErrors[j].getUnit());
}
super.Low[j] = (float) Low[j];
super.Hi[j] = (float) Hi[j];
}
}
public void cram_missing(boolean[] range_select) {
int n = Math.min(range_select.length, Samples[0].length);
for (int i=0; i<n; i++) {
if (!range_select[i]) Samples[0][i] = Double.NaN;
}
}
public boolean isMissing() {
return (Samples == null);
}
public boolean equals(Object set) {
if (!(set instanceof Gridded2DDoubleSet) || set == null) return false;
if (this == set) return true;
if (testNotEqualsCache((Set) set)) return false;
if (testEqualsCache((Set) set)) return true;
if (!equalUnitAndCS((Set) set)) return false;
try {
int i, j;
if (DomainDimension != ((Gridded2DDoubleSet) set).getDimension() ||
ManifoldDimension !=
((Gridded2DDoubleSet) set).getManifoldDimension() ||
Length != ((Gridded2DDoubleSet) set).getLength()) return false;
for (j=0; j<ManifoldDimension; j++) {
if (Lengths[j] != ((Gridded2DDoubleSet) set).getLength(j)) {
return false;
}
}
// Sets are immutable, so no need for 'synchronized'
double[][] samples = ((Gridded2DDoubleSet) set).getDoubles(false);
if (Samples != null && samples != null) {
for (j=0; j<DomainDimension; j++) {
for (i=0; i<Length; i++) {
if (Samples[j][i] != samples[j][i]) {
addNotEqualsCache((Set) set);
return false;
}
}
}
}
else {
double[][] this_samples = getDoubles(false);
if (this_samples == null) {
if (samples != null) {
return false;
}
} else if (samples == null) {
return false;
} else {
for (j=0; j<DomainDimension; j++) {
for (i=0; i<Length; i++) {
if (this_samples[j][i] != samples[j][i]) {
addNotEqualsCache((Set) set);
return false;
}
}
}
}
}
addEqualsCache((Set) set);
return true;
}
catch (VisADException e) {
return false;
}
}
/**
* Clones this instance.
*
* @return A clone of this instance.
*/
public Object clone() {
Gridded2DDoubleSet clone = (Gridded2DDoubleSet)super.clone();
if (Samples != null) {
/*
* The Samples array is cloned because getDoubles(false) allows clients
* to manipulate the array and the general clone() contract forbids
* cross-clone contamination.
*/
clone.Samples = (double[][])Samples.clone();
for (int i = 0; i < Samples.length; i++)
clone.Samples[i] = (double[])Samples[i].clone();
}
return clone;
}
public Object cloneButType(MathType type) throws VisADException {
if (ManifoldDimension == 2) {
return new Gridded2DDoubleSet(type, Samples, LengthX, LengthY,
DomainCoordinateSystem, SetUnits, SetErrors);
}
else {
return new Gridded2DDoubleSet(type, Samples, LengthX,
DomainCoordinateSystem, SetUnits, SetErrors);
}
}
/* WLH 3 April 2003
public Object cloneButType(MathType type) throws VisADException {
return new Gridded2DDoubleSet(type, Samples, Length,
DomainCoordinateSystem, SetUnits, SetErrors);
}
*/
}