//
// VisADIndexedTriangleStripArray.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;
/**
VisADIndexedTriangleStripArray stands in for
j3d.IndexedTriangleStripArray and is Serializable.<P>
*/
public class VisADIndexedTriangleStripArray extends VisADGeometryArray {
public int indexCount; // should = indices.length
public int[] indices;
public int[] stripVertexCounts;
public static VisADIndexedTriangleStripArray
merge(VisADIndexedTriangleStripArray[] arrays)
throws VisADException {
if (arrays == null || arrays.length == 0) return null;
VisADIndexedTriangleStripArray array =
new VisADIndexedTriangleStripArray();
merge(arrays, array);
int count = 0;
int nind = 0;
int nstrips = 0;
int n = arrays.length;
// WLH 1 May 99
int[] start = new int[n];
start[0] = 0;
for (int i=0; i<n; i++) {
if (arrays[i] != null) {
count += arrays[i].indexCount;
nind += arrays[i].indices.length;
nstrips += arrays[i].stripVertexCounts.length;
// WLH 1 May 99
if (i > 0) start[i] = start[i-1] + arrays[i-1].vertexCount;
}
}
if (nstrips <= 0) return null;
int[] indices = new int[nind];
int[] stripVertexCounts = new int[nstrips];
nind = 0;
nstrips = 0;
for (int i=0; i<n; i++) {
if (arrays[i] != null) {
int incind = arrays[i].indices.length;
int incnstrips = arrays[i].stripVertexCounts.length;
for (int j=0; j<incind; j++) {
// WLH 1 May 99
// indices[nind + j] = arrays[i].indices[j];
indices[nind + j] = arrays[i].indices[j] + start[i];
}
for (int j=0; j<incnstrips; j++) {
stripVertexCounts[nstrips + j] = arrays[i].stripVertexCounts[j];
}
nind += incind;
nstrips += incnstrips;
}
}
array.indexCount = count;
array.indices = indices;
array.stripVertexCounts = stripVertexCounts;
return array;
}
private static final int MUL = 6;
public VisADGeometryArray adjustLongitude(DataRenderer renderer)
throws VisADException {
float[] lons = getLongitudes(renderer);
if (lons == null) return this;
int[] axis = new int[1];
float[] lon_coords = new float[2];
float[] lon_range = getLongitudeRange(lons, axis, lon_coords);
if (lon_range[0] != lon_range[0] ||
lon_range[1] != lon_range[1]) return this;
float bottom = lon_range[0];
float top = lon_range[1];
float low = bottom + 30.0f;
float hi = top - 30.0f;
int lon_axis = axis[0];
float coord_bottom = lon_coords[0];
float coord_top = lon_coords[1];
// midpoint from this (if this_split)
int mid_first = -1;
int mid_second = -1;
// save midpoint from last (if last_split)
int last_mid_first = -1;
int last_mid_second = -1;
// midpoint between -3 and +3 (if this_split^last_split)
int sillymid_first = -1;
int sillymid_second = -1;
// most recent point
int last = -1;
// point before most recent
int early = -1;
// this point
int point = -1;
VisADIndexedTriangleStripArray array = new VisADIndexedTriangleStripArray();
// worst case makes 3 times as many triangles
float[] coords = new float[MUL * coordinates.length];
System.arraycopy(coordinates, 0, coords, 0, coordinates.length);
float[] nos = null;
if (normals != null) {
nos = new float[MUL * normals.length];
System.arraycopy(normals, 0, nos, 0, normals.length);
}
int color_length = 0;
byte[] cols = null;
if (colors != null) {
color_length = 3;
cols = new byte[MUL * colors.length];
if (colors.length != coordinates.length) color_length = 4;
System.arraycopy(colors, 0, cols, 0, colors.length);
}
float[] texs = null;
if (texCoords != null) {
texs = new float[MUL * texCoords.length];
System.arraycopy(texCoords, 0, texs, 0, texCoords.length);
}
int coord_index = coordinates.length / 3; // index to add next point
// worst case makes 3 times as many indices
int[] inds = new int[MUL * indices.length];
int ind_index = 0; // index to add next indices entry
// worst case makes as many strips as there were points
int[] svcs = new int[coordinates.length];
int svc_index = 0;
int last_i = 0; // start i for each vertex strip
// int m = 0; replaced by: ind_index
boolean any_split = false;
for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) {
boolean this_split = false;
int accum = 0; // strip counter
for (int i=last_i; i<last_i+stripVertexCounts[i_svc]-1; i++) {
boolean last_split = this_split; // true if last edge was split
if (last_split) {
last_mid_first = mid_first;
last_mid_second = mid_second;
}
if ((lons[indices[i]] < low && hi < lons[indices[i+1]]) ||
(lons[indices[i+1]] < low && hi < lons[indices[i]])) {
this_split = true;
any_split = true;
if (lon_axis < 0) {
// not enough info to interpolate, so treat split as a break
if (accum >= 3) {
svcs[svc_index] = accum;
svc_index++;
}
last = indices[i+1];
accum = 1; // reset strip counter;
continue;
}
// lon_axis >= 0
// split line by interpolation
float a, b;
float coord_first, coord_second;
if (lons[indices[i]] < low) {
a = lons[indices[i]] - bottom;
b = top - lons[indices[i+1]];
coord_first = coord_bottom;
coord_second = coord_top;
}
else {
a = top - lons[indices[i]];
b = lons[indices[i+1]] - bottom;
coord_first = coord_top;
coord_second = coord_bottom;
}
float alpha = b / (a + b);
alpha = (alpha != alpha || alpha < 0.0f) ? 0.0f :
((1.0f < alpha) ? 1.0f : alpha);
float beta = 1.0f - alpha;
mid_first = coord_index++;
mid_second = coord_index++;
int f3 = 3 * mid_first;
int s3 = 3 * mid_second;
int i3 = 3 * indices[i];
int ip3 = 3 * indices[i+1];
coords[f3] = alpha * coordinates[i3] + beta * coordinates[ip3];
coords[f3+1] = alpha * coordinates[i3+1] + beta * coordinates[ip3+1];
coords[f3+2] = alpha * coordinates[i3+2] + beta * coordinates[ip3+2];
coords[s3] = coords[f3];
coords[s3+1] = coords[f3+1];
coords[s3+2] = coords[f3+2];
coords[f3+lon_axis] = coord_first;
coords[s3+lon_axis] = coord_second;
if (normals != null) {
nos[f3] = alpha * normals[i3] + beta * normals[ip3];
nos[f3+1] = alpha * normals[i3+1] + beta * normals[ip3+1];
nos[f3+2] = alpha * normals[i3+2] + beta * normals[ip3+2];
nos[s3] = nos[f3];
nos[s3+1] = nos[f3+1];
nos[s3+2] = nos[f3+2];
}
if (color_length == 3) {
cols[f3] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[i3]) +
beta * ShadowType.byteToFloat(colors[ip3]));
cols[f3+1] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[i3+1]) +
beta * ShadowType.byteToFloat(colors[ip3+1]));
cols[f3+2] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[i3+2]) +
beta * ShadowType.byteToFloat(colors[ip3+2]));
cols[s3] = cols[f3];
cols[s3+1] = cols[f3+1];
cols[s3+2] = cols[f3+2];
}
else if (color_length == 4) {
int f4 = 4 * mid_first;
int s4 = 4 * mid_second;
int i4 = 4 * indices[i];
int ip4 = 4 * indices[i+1];
cols[f4] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[i4]) +
beta * ShadowType.byteToFloat(colors[ip4]));
cols[f4+1] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[i4+1]) +
beta * ShadowType.byteToFloat(colors[ip4+1]));
cols[f4+2] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[i4+2]) +
beta * ShadowType.byteToFloat(colors[ip4+2]));
cols[f4+3] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[i4+3]) +
beta * ShadowType.byteToFloat(colors[ip4+3]));
cols[s4] = cols[f4];
cols[s4+1] = cols[f4+1];
cols[s4+2] = cols[f4+2];
cols[s4+3] = cols[f4+3];
}
if (texCoords != null) {
int f2 = 2 * mid_first;
int s2 = 2 * mid_second;
int i2 = 2 * indices[i];
int ip2 = 2 * indices[i+1];
texs[f2] = alpha * texCoords[i2] + beta * texCoords[ip2];
texs[f2+1] = alpha * texCoords[i2+1] + beta * texCoords[ip2+1];
texs[s2] = cols[f2];
texs[s2+1] = cols[f2+1];
}
}
else { // no split
this_split = false;
}
if (accum > 0 && this_split != last_split && lon_axis >= 0) {
// need to compute mid edge from -3 to +3
// split line by interpolation
float a, b;
float coord_first, coord_second;
if (lons[indices[i-1]] < low) {
a = lons[indices[i-1]] - bottom;
b = top - lons[indices[i+1]];
coord_first = coord_bottom;
coord_second = coord_top;
}
else {
a = top - lons[indices[i-1]];
b = lons[indices[i+1]] - bottom;
coord_first = coord_top;
coord_second = coord_bottom;
}
float alpha = b / (a + b);
alpha = (alpha != alpha || alpha < 0.0f) ? 0.0f :
((1.0f < alpha) ? 1.0f : alpha);
float beta = 1.0f - alpha;
sillymid_first = coord_index++;
sillymid_second = coord_index++;
int f3 = 3 * sillymid_first;
int s3 = 3 * sillymid_second;
int im3 = 3 * indices[i-1];
int ip3 = 3 * indices[i+1];
coords[f3] = alpha * coordinates[im3] + beta * coordinates[ip3];
coords[f3+1] = alpha * coordinates[im3+1] + beta * coordinates[ip3+1];
coords[f3+2] = alpha * coordinates[im3+2] + beta * coordinates[ip3+2];
coords[s3] = coords[f3];
coords[s3+1] = coords[f3+1];
coords[s3+2] = coords[f3+2];
coords[f3+lon_axis] = coord_first;
coords[s3+lon_axis] = coord_second;
if (normals != null) {
nos[f3] = alpha * normals[im3] + beta * normals[ip3];
nos[f3+1] = alpha * normals[im3+1] + beta * normals[ip3+1];
nos[f3+2] = alpha * normals[im3+2] + beta * normals[ip3+2];
nos[s3] = nos[f3];
nos[s3+1] = nos[f3+1];
nos[s3+2] = nos[f3+2];
}
if (color_length == 3) {
cols[f3] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[im3]) +
beta * ShadowType.byteToFloat(colors[ip3]));
cols[f3+1] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[im3+1]) +
beta * ShadowType.byteToFloat(colors[ip3+1]));
cols[f3+2] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[im3+2]) +
beta * ShadowType.byteToFloat(colors[ip3+2]));
cols[s3] = cols[f3];
cols[s3+1] = cols[f3+1];
cols[s3+2] = cols[f3+2];
}
else if (color_length == 4) {
int f4 = 4 * mid_first;
int s4 = 4 * mid_second;
int im4 = 4 * indices[i-1];
int ip4 = 4 * indices[i+1];
cols[f4] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[im4]) +
beta * ShadowType.byteToFloat(colors[ip4]));
cols[f4+1] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[im4+1]) +
beta * ShadowType.byteToFloat(colors[ip4+1]));
cols[f4+2] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[im4+2]) +
beta * ShadowType.byteToFloat(colors[ip4+2]));
cols[f4+3] = ShadowType.floatToByte(
alpha * ShadowType.byteToFloat(colors[im4+3]) +
beta * ShadowType.byteToFloat(colors[ip4+3]));
cols[s4] = cols[f4];
cols[s4+1] = cols[f4+1];
cols[s4+2] = cols[f4+2];
cols[s4+3] = cols[f4+3];
}
if (texCoords != null) {
int f2 = 2 * mid_first;
int s2 = 2 * mid_second;
int im2 = 2 * indices[i-1];
int ip2 = 2 * indices[i+1];
texs[f2] = alpha * texCoords[im2] + beta * texCoords[ip2];
texs[f2+1] = alpha * texCoords[im2+1] + beta * texCoords[ip2+1];
texs[s2] = cols[f2];
texs[s2+1] = cols[f2+1];
}
}
if (this_split) {
if (accum == 0) {
early = mid_second;
last = indices[i+1];
accum = 2;
continue; // don't make any triangles yet, for accum = 0
} // end if (accum == 0)
else if (last_split) { // && this_split
point = mid_first;
accum++;
if (accum == 3) {
inds[ind_index++] = early;
inds[ind_index++] = last;
inds[ind_index++] = point;
}
else {
inds[ind_index++] = point;
}
// bind off
svcs[svc_index] = accum;
svc_index++;
// accum = 0, but more to come
// create a 2-triangle strip
// (last_mid_first, i-3, mid_second, i+3)
early = last_mid_first;
last = indices[i-1];
point = mid_second;
accum = 3;
inds[ind_index++] = early;
inds[ind_index++] = last;
inds[ind_index++] = point;
point = indices[i+1];
accum++;
inds[ind_index++] = point;
}
else { // !last_split && accum > 0 && this_split
// add (mid_first, i-3, sillymid_first)
point = mid_first;
accum++;
if (accum == 2) {
early = last;
last = point;
}
else if (accum == 3) {
inds[ind_index++] = early;
inds[ind_index++] = last;
inds[ind_index++] = point;
}
else {
inds[ind_index++] = point;
}
point = indices[i-1];
accum++;
if (accum == 2) {
early = last;
last = point;
}
else if (accum == 3) {
inds[ind_index++] = early;
inds[ind_index++] = last;
inds[ind_index++] = point;
}
else {
inds[ind_index++] = point;
}
point = sillymid_first;
accum++;
if (accum == 2) {
early = last;
last = point;
}
else if (accum == 3) {
inds[ind_index++] = early;
inds[ind_index++] = last;
inds[ind_index++] = point;
}
else {
inds[ind_index++] = point;
}
// (accum >= 3)
svcs[svc_index] = accum;
svc_index++;
// accum = 0, but more to come
// start a triangle strip
// (sillymid_second, mid_second, i+3)
early = sillymid_second;
last = mid_second;
point = indices[i+1];
accum = 3;
inds[ind_index++] = early;
inds[ind_index++] = last;
inds[ind_index++] = point;
}
}
else { // !this_split
if (accum == 0) {
early = indices[i];
last = indices[i+1];
accum = 2;
continue; // don't make any triangles yet, for accum = 0
} // end if (accum == 0)
else if (last_split && lon_axis >= 0) { // && !this_split
// first, bind off
if (accum >= 3) {
svcs[svc_index] = accum;
svc_index++;
}
// accum = 0, but more to come
early = indices[i-1];
last = last_mid_first;
point = sillymid_first;
accum = 3;
inds[ind_index++] = early;
inds[ind_index++] = last;
inds[ind_index++] = point;
// bind off again
svcs[svc_index] = accum;
svc_index++;
// accum = 0, but more to come
// create a 2-triangle strip
// (last_mid_second, sillymid_second, i, i+3)
early = last_mid_second;
last = sillymid_second;
point = indices[i];
accum = 3;
inds[ind_index++] = early;
inds[ind_index++] = last;
inds[ind_index++] = point;
point = indices[i+1];
accum++;
inds[ind_index++] = point;
}
else { // (!last_split || lon_axis < 0) && accum > 0 && !this_split
// just add the next point (i+3)
point = indices[i+1];
accum++;
if (accum == 2) {
early = last;
last = point;
}
else if (accum == 3) {
inds[ind_index++] = early;
inds[ind_index++] = last;
inds[ind_index++] = point;
}
else {
inds[ind_index++] = point;
}
}
} // end if no split
} // end for (int i=last_i; i<last_i+stripVertexCounts[i_svc]-1; i++)
if (accum >= 3) {
svcs[svc_index] = accum;
svc_index++;
}
last_i += stripVertexCounts[i_svc];
} // end for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++)
if (!any_split) {
return this;
}
else {
array.coordinates = new float[3 * coord_index];
System.arraycopy(coords, 0, array.coordinates, 0, 3 * coord_index);
if (normals != null) {
array.normals = new float[3 * coord_index];
System.arraycopy(nos, 0, array.normals, 0, 3 * coord_index);
}
if (colors != null) {
array.colors = new byte[color_length * coord_index];
System.arraycopy(cols, 0, array.colors, 0, color_length * coord_index);
}
if (texCoords != null) {
array.texCoords = new float[2 * coord_index];
System.arraycopy(texs, 0, array.texCoords, 0, 2 * coord_index);
}
array.vertexCount = coord_index;
array.stripVertexCounts = new int[svc_index];
System.arraycopy(svcs, 0, array.stripVertexCounts, 0, svc_index);
array.indices = new int[ind_index];
System.arraycopy(inds, 0, array.indices, 0, ind_index);
return array;
}
}
public VisADGeometryArray removeMissing() {
VisADIndexedTriangleStripArray array =
new VisADIndexedTriangleStripArray();
float[] coords = new float[coordinates.length];
float[] nos = null;
if (normals != null) {
nos = new float[normals.length];
}
int color_length = 3;
byte[] cols = null;
if (colors != null) {
cols = new byte[colors.length];
if (colors.length != coordinates.length) color_length = 4;
}
float[] texs = null;
if (texCoords != null) {
texs = new float[texCoords.length];
}
int[] compress = new int[indices.length];
int j = 0;
int k = 0;
for (int i=0; i<coordinates.length; i+=3) {
if (coordinates[i] == coordinates[i] &&
coordinates[i+1] == coordinates[i+1] &&
coordinates[i+2] == coordinates[i+2]) {
compress[j] = k;
int k3 = 3 * k;
coords[k3] = coordinates[i];
coords[k3+1] = coordinates[i+1];
coords[k3+2] = coordinates[i+2];
if (normals != null) {
nos[k3] = normals[i];
nos[k3+1] = normals[i+1];
nos[k3+2] = normals[i+2];
}
if (colors != null) {
int kc = color_length * k;
int ic = color_length * j;
cols[kc] = colors[ic];
cols[kc+1] = colors[ic+1];
cols[kc+2] = colors[ic+2];
if (color_length == 4) {
cols[kc+3] = colors[ic+3];
}
}
if (texCoords != null) {
int kt = 2 * k;
int it = 2 * j;
texs[kt] = texCoords[it];
texs[kt+1] = texCoords[it+1];
}
k++;
}
else { // missing coordinates
compress[j] = -1;
}
j++;
} // end for (int i=0; i<coordinates.length; i+=3)
array.coordinates = new float[3 * k];
System.arraycopy(coords, 0, array.coordinates, 0, 3 * k);
if (normals != null) {
array.normals = new float[3 * k];
System.arraycopy(nos, 0, array.normals, 0, 3 * k);
}
if (colors != null) {
array.colors = new byte[color_length * k];
System.arraycopy(cols, 0, array.colors, 0, color_length * k);
}
if (texCoords != null) {
array.texCoords = new float[2 * k];
System.arraycopy(texs, 0, array.texCoords, 0, 2 * k);
}
array.vertexCount = k;
int[] new_indices = new int[indices.length];
int[] svcs = new int[coordinates.length / 4];
int svc_index = 0;
int last_i = 0; // start i for each vertex strip
int m = 0;
boolean any_missing = false;
for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) {
int accum = 0;
for (int i=last_i; i<last_i+stripVertexCounts[i_svc]; i++) {
if (compress[indices[i]] >= 0) {
accum++;
if (accum >= 3) {
int iml = i;
if (accum == 3) {
iml = i - 2;
}
for (int im=iml; im<=i; im++) {
new_indices[m] = compress[indices[im]];
m++;
} // end for (im=iml; im<=i; im+=3)
} // end if (accum >= 3)
}
else { // missing coordinates values
any_missing = true;
if (accum >= 3) {
svcs[svc_index] = accum;
svc_index++;
}
accum = 0; // reset strip counter;
}
} // end for (int i=last_i; i<last_i+stripVertexCounts[i_svc]; i++)
if (accum >= 3) {
svcs[svc_index] = accum;
svc_index++;
}
last_i += stripVertexCounts[i_svc];
} // end for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++)
if (!any_missing) {
return this;
}
else {
array.indices = new int[m];
System.arraycopy(new_indices, 0, array.indices, 0, m);
array.stripVertexCounts = new int[svc_index];
System.arraycopy(svcs, 0, array.stripVertexCounts, 0, svc_index);
return array;
}
}
public String toString() {
/*
String string = "VisADIndexedTriangleStripArray\n" + super.toString() +
"\n indexCount = " + indexCount;
*/
String string = "VisADIndexedTriangleStripArray, indexCount = " + indexCount;
string = string + "\n stripVertexCounts = ";
for (int i=0; i<stripVertexCounts.length; i++) {
string = string + stripVertexCounts[i] + " ";
}
string = string + "\n indices = ";
for (int i=0; i<indices.length; i++) {
string = string + indices[i] + " ";
}
return string;
}
public Object clone() {
VisADIndexedTriangleStripArray array =
new VisADIndexedTriangleStripArray();
copy(array);
array.indexCount = indexCount;
if (stripVertexCounts != null) {
array.stripVertexCounts = new int[stripVertexCounts.length];
System.arraycopy(stripVertexCounts, 0, array.stripVertexCounts, 0,
stripVertexCounts.length);
}
if (indices != null) {
array.indices = new int[indices.length];
System.arraycopy(indices, 0, array.indices, 0, indices.length);
}
return array;
}
}