//
// VisADLineArray.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;
/**
VisADLineArray stands in for j3d.LineArray
and is Serializable.<P>
*/
public class VisADLineArray extends VisADGeometryArray {
/**
* Merge an array of VisADLineArrays into a single VisADLineArray.
* @param arrays array of VisADLineArrays (may be null)
* @return a single VisADLineArray with all the info of arrays.
* returns null if input is null.
*/
public static VisADLineArray merge(VisADLineArray[] arrays)
throws VisADException {
if (arrays == null || arrays.length == 0) return null;
VisADLineArray array = new VisADLineArray();
merge(arrays, array);
/*
int n = arrays.length;
int count = 0;
boolean color_flag = (arrays[0].colors != null);
for (int i=0; i<n; i++) {
count += arrays[i].vertexCount;
if (color_flag != (arrays[i].colors != null)) {
throw new DisplayException("VisADLineArray.merge: formats don't match");
}
}
float[] coordinates = new float[3 * count];
byte[] colors = null;
if (color_flag) {
colors = new byte[3 * count];
}
int k = 0;
int m = 0;
for (int i=0; i<n; i++) {
float[] c = arrays[i].coordinates;
for (int j=0; j<3*arrays[i].vertexCount; j++) {
coordinates[k++] = c[j];
}
if (color_flag) {
byte[] b = arrays[i].colors;
for (int j=0; j<3*arrays[i].vertexCount; j++) {
colors[m++] = b[j];
}
}
}
VisADLineArray array = new VisADLineArray();
array.vertexCount = count;
array.coordinates = coordinates;
array.colors = colors;
array.vertexFormat = arrays[0].vertexFormat;
*/
return array;
}
public VisADGeometryArray adjustLongitude(DataRenderer renderer)
throws VisADException {
float[] lons = getLongitudes(renderer);
if (any_longitude_rotate) {
VisADLineArray array = new VisADLineArray();
array.vertexCount = vertexCount;
array.coordinates = coordinates;
array.colors = colors;
return array;
}
else {
return this;
}
}
private final static double LIMIT = 1.0f; // constant for TEST = 0
private final static double ALPHA = 0.01f; // constant for TEST = 1
/** eliminate any vectors or triangles crossing seams of
map projections, defined by display-side CoordinateSystems;
this default implementation does nothing */
public VisADGeometryArray adjustSeam(DataRenderer renderer)
throws VisADException {
CoordinateSystem coord_sys = renderer.getDisplayCoordinateSystem();
if (coord_sys == null ||
coord_sys instanceof SphericalCoordinateSystem ||
coord_sys instanceof CylindricalCoordinateSystem ||
coordinates == null) {
return this;
}
int len = coordinates.length / 3;
// WLH 15 March 2000
if (len < 6) return this;
// System.out.println("VisADLineArray.adjustSeam try");
double[][] cs = new double[3][len];
int j = 0;
for (int i=0; i<len; i++) {
cs[0][i] = coordinates[j++];
cs[1][i] = coordinates[j++];
cs[2][i] = coordinates[j++];
}
double[][] rs = coord_sys.fromReference(Set.copyDoubles (cs));
boolean[] test = new boolean[len];
int last_i;
boolean any_split = false;
// TEST 1
if (len < 2) return this;
double[][] bs = new double[3][len/2];
double[][] ss = new double[3][len/2];
// ALPHA = 0.01f
double ALPHA1 = 1.0f + ALPHA;
double ALPHA1m = 1.0f - ALPHA;
for (int i=0; i<len/2; i++) {
// BS = point ALPHA * opposite direction
// bs = pt_i + 0.01 * (pt_i - pt_ip1), not ref
bs[0][i] = ALPHA1 * rs[0][2*i] - ALPHA * rs[0][2*i+1];
bs[1][i] = ALPHA1 * rs[1][2*i] - ALPHA * rs[1][2*i+1];
bs[2][i] = ALPHA1 * rs[2][2*i] - ALPHA * rs[2][2*i+1];
// SS = point ALPHA * same direction
// ss = pt_ip1 + 0.01 * (pt_ip1 - pt_i), not ref
ss[0][i] = ALPHA1 * rs[0][2*i+1] - ALPHA * rs[0][2*i];
ss[1][i] = ALPHA1 * rs[1][2*i+1] - ALPHA * rs[1][2*i];
ss[2][i] = ALPHA1 * rs[2][2*i+1] - ALPHA * rs[2][2*i];
}
double[][] ds = coord_sys.toReference(bs);
// ds = pt_i + 0.01 * (pt_i - pt_ip1), ref
double[][] es = coord_sys.toReference(ss);
// es = pt_ip1 + 0.01 * (pt_ip1 - pt_i), ref
double IALPHA = 1.0f / ALPHA;
for (int i=0; i<len; i+=2) {
// a = original line segment, ref
// a = pt_ip1 - pt_i, ref
double a0 = cs[0][i+1] - cs[0][i];
double a1 = cs[1][i+1] - cs[1][i];
double a2 = cs[2][i+1] - cs[2][i];
// b = estimate of vector using ALPHA * opposite direction
// b = 100.0 * (pt_i - toRef(pt_i + 0.01 * (pt_i - pt_ip1)) )
// if no break, b = pt_ip1 - pt_i, ref
double b0 = IALPHA * (cs[0][i] - ds[0][i/2]);
double b1 = IALPHA * (cs[1][i] - ds[1][i/2]);
double b2 = IALPHA * (cs[2][i] - ds[2][i/2]);
double aa = (a0 * a0 + a1 * a1 + a2 * a2);
double aminusb =
(b0 - a0) * (b0 - a0) +
(b1 - a1) * (b1 - a1) +
(b2 - a2) * (b2 - a2);
double abratio = aminusb / aa;
// c = estimate of vector using ALPHA * opposite direction
// c = 100.0 * (pt_ip1 - toRef(pt_ip1 + 0.01 * (pt_ip1 - pt_i)) )
// if no break, c = pti - pt_ip1, ref
double c0 = IALPHA * (cs[0][i+1] - es[0][i/2]);
double c1 = IALPHA * (cs[1][i+1] - es[1][i/2]);
double c2 = IALPHA * (cs[2][i+1] - es[2][i/2]);
double aminusc =
(c0 + a0) * (c0 + a0) +
(c1 + a1) * (c1 + a1) +
(c2 + a2) * (c2 + a2);
double acratio = aminusc / aa;
// true for bad segment
test[i] = (0.01f < abratio) || (0.01f < acratio);
/*
if ((0.01f < abratio) != (0.01f < acratio)) {
System.out.println("test[" + i + "] " + abratio + " " + acratio);
}
*/
if (test[i]) any_split = true;
} // end for (int i=0; i<len; i+=2)
bs = null;
ss = null;
if (!any_split) {
return this;
}
// TEST 0
double[] lengths = new double[len];
for (int i=0; i<len; i++) lengths[i] = 0.0f;
double mean_length = 0.0f;
double var_length = 0.0f;
double max_length = 0.0f;
int num_length = 0;
for (int i=0; i<len; i+=2) {
double cd = (cs[0][i+1] - cs[0][i]) * (cs[0][i+1] - cs[0][i]) +
(cs[1][i+1] - cs[1][i]) * (cs[1][i+1] - cs[1][i]) +
(cs[2][i+1] - cs[2][i]) * (cs[2][i+1] - cs[2][i]);
if (!test[i]) {
lengths[i] = cd;
num_length++;
mean_length += lengths[i];
var_length += lengths[i] * lengths[i];
if (lengths[i] > max_length) max_length = lengths[i];
}
} // end for (int i=0; i<len; i+=2)
if (num_length < 2) return this;
mean_length = mean_length / num_length;
var_length = (double)
Math.sqrt((var_length - mean_length * mean_length) / num_length);
double limit_length = mean_length + LIMIT * var_length;
/**TDR, TEST0 causes some problems...come back to this.
System.out.println("limit_length = " + limit_length + " " + max_length + " " +
mean_length + " " + var_length + " " + num_length);
if (max_length >= limit_length) {
for (int i=0; i<len; i+=2) {
test[i] = test[i] || (lengths[i] > limit_length);
}
}
*/
cs = null;
rs = null;
float[] lastcoord = null;
byte[] lastcol = null;
VisADLineArray array = new VisADLineArray();
// worst case splits every line
float[] coords = new float[3 * coordinates.length];
int color_length = 0;
byte[] cols = null;
if (colors != null) {
color_length = 3;
cols = new byte[3 * colors.length];
if (colors.length != coordinates.length) color_length = 4;
}
int ki = 0;
int kj = 0;
j = 0;
for (int i=0; i<3*len; i+=6) {
if (!test[i/3]) {
coords[ki] = coordinates[i];
coords[ki+1] = coordinates[i+1];
coords[ki+2] = coordinates[i+2];
coords[ki+3] = coordinates[i+3];
coords[ki+4] = coordinates[i+4];
coords[ki+5] = coordinates[i+5];
ki += 6;
if (color_length == 3) {
cols[kj] = colors[j];
cols[kj+1] = colors[j+1];
cols[kj+2] = colors[j+2];
cols[kj+3] = colors[j+3];
cols[kj+4] = colors[j+4];
cols[kj+5] = colors[j+5];
kj += 6;
}
else if (color_length == 4) {
cols[kj] = colors[j];
cols[kj+1] = colors[j+1];
cols[kj+2] = colors[j+2];
cols[kj+3] = colors[j+3];
cols[kj+4] = colors[j+4];
cols[kj+5] = colors[j+5];
cols[kj+6] = colors[j+6];
cols[kj+7] = colors[j+7];
kj += 8;
}
}
else {
any_split = true;
}
j += 2 * color_length;
}
//System.out.println("VisADLineArray.adjustSeam any_split = " + any_split);
if (!any_split) {
return this;
}
else {
array.vertexCount = ki / 3;
array.coordinates = new float[ki];
System.arraycopy(coords, 0, array.coordinates, 0, ki);
if (colors != null) {
array.colors = new byte[kj];
System.arraycopy(cols, 0, array.colors, 0, kj);
}
return array;
}
}
public VisADGeometryArray removeMissing() {
VisADLineArray array = new VisADLineArray();
float[] coords = new float[coordinates.length];
int color_length = 3;
byte[] cols = null;
if (colors != null) {
cols = new byte[colors.length];
if (colors.length != coordinates.length) color_length = 4;
}
int k = 0;
int m = 0;
int j = 0;
boolean any_missing = false;
for (int i=0; i<coordinates.length; i+=6) {
if (coordinates[i] == coordinates[i] &&
coordinates[i+1] == coordinates[i+1] &&
coordinates[i+2] == coordinates[i+2] &&
coordinates[i+3] == coordinates[i+3] &&
coordinates[i+4] == coordinates[i+4] &&
coordinates[i+5] == coordinates[i+5] &&
!Float.isInfinite(coordinates[i]) &&
!Float.isInfinite(coordinates[i+1]) &&
!Float.isInfinite(coordinates[i+2]) &&
!Float.isInfinite(coordinates[i+3]) &&
!Float.isInfinite(coordinates[i+4]) &&
!Float.isInfinite(coordinates[i+5])) {
coords[k] = coordinates[i];
coords[k+1] = coordinates[i+1];
coords[k+2] = coordinates[i+2];
coords[k+3] = coordinates[i+3];
coords[k+4] = coordinates[i+4];
coords[k+5] = coordinates[i+5];
if (colors != null) {
cols[m] = colors[j];
cols[m+1] = colors[j+1];
cols[m+2] = colors[j+2];
m += 3;
if (color_length == 4) {
cols[m++] = colors[j+3];
}
cols[m] = colors[j+color_length];
cols[m+1] = colors[j+color_length+1];
cols[m+2] = colors[j+color_length+2];
m += 3;
if (color_length == 4) {
cols[m++] = colors[j+color_length+3];
}
}
k += 6;
}
else { // missing coordinates values
any_missing = true;
}
j += 2 * color_length;
}
if (!any_missing) {
return this;
}
else {
array.coordinates = new float[k];
System.arraycopy(coords, 0, array.coordinates, 0, k);
if (colors != null) {
array.colors = new byte[m];
System.arraycopy(cols, 0, array.colors, 0, m);
}
return array;
}
}
/**
* Clone this VisADLineArray
* @return clone of this
*/
public Object clone() {
VisADLineArray array = new VisADLineArray();
copy(array);
return array;
}
}