// // VisADLineStripArray.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; /** VisADLineStripArray stands in for j3d.LineStripArray and is Serializable.<P> */ public class VisADLineStripArray extends VisADGeometryArray { public int[] stripVertexCounts; public static VisADLineStripArray merge(VisADLineStripArray[] arrays) throws VisADException { if (arrays == null || arrays.length == 0) return null; VisADLineStripArray array = new VisADLineStripArray(); merge(arrays, array); int n = arrays.length; int nstrips = 0; for (int i=0; i<n; i++) { if (arrays[i] != null) { nstrips += arrays[i].stripVertexCounts.length; } } if (nstrips <= 0) return null; int[] stripVertexCounts = new int[nstrips]; nstrips = 0; for (int i=0; i<n; i++) { if (arrays[i] != null) { int incnstrips = arrays[i].stripVertexCounts.length; for (int j=0; j<incnstrips; j++) { stripVertexCounts[nstrips + j] = arrays[i].stripVertexCounts[j]; } nstrips += incnstrips; } } array.stripVertexCounts = stripVertexCounts; return array; } private final static int TEST = 1; private final static float LIMIT = 4.0f; // constant for TEST = 0 private final static float ALPHA = 0.1f; // constant for TEST = 1 public VisADGeometryArray adjustSeam(DataRenderer renderer) throws VisADException { CoordinateSystem coord_sys = renderer.getDisplayCoordinateSystem(); // DRM 19 March 2002 //if (coord_sys == null || coord_sys instanceof SphericalCoordinateSystem) { // return this; //} if (coord_sys == null || coord_sys instanceof SphericalCoordinateSystem || coordinates == null) { return this; } int len = coordinates.length / 3; // WLH 15 March 2000 if (len < 6) return this; float[][] cs = new float[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++]; } float[][] rs = coord_sys.fromReference(Set.copyFloats (cs)); boolean[] test = new boolean[len]; int last_i; if (TEST == 0) { float[] ratios = new float[len]; for (int i=0; i<len; i++) ratios[i] = 0.0f; float mean_ratio = 0.0f; float var_ratio = 0.0f; float max_ratio = 0.0f; int num_ratio = 0; last_i = 0; // start i for each vertex strip for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) { for (int i=last_i; i<last_i+stripVertexCounts[i_svc]-1; i++) { float 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]); float rd = (rs[0][i+1] - rs[0][i]) * (rs[0][i+1] - rs[0][i]) + (rs[1][i+1] - rs[1][i]) * (rs[1][i+1] - rs[1][i]) + (rs[2][i+1] - rs[2][i]) * (rs[2][i+1] - rs[2][i]); if (rd > 0.0f) { ratios[i] = cd / rd; num_ratio++; mean_ratio += ratios[i]; var_ratio += ratios[i] * ratios[i]; if (ratios[i] > max_ratio) max_ratio = ratios[i]; } } // end for (int i=last_i; i<last_i+stripVertexCounts[i_svc]*3; i+=3) last_i += stripVertexCounts[i_svc]; } // end for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) if (num_ratio < 2) return this; mean_ratio = mean_ratio / num_ratio; var_ratio = (float) Math.sqrt((var_ratio - mean_ratio * mean_ratio) / num_ratio); float limit_ratio = mean_ratio + LIMIT * var_ratio; if (max_ratio < limit_ratio) return this; last_i = 0; // start i for each vertex strip for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) { for (int i=last_i; i<last_i+stripVertexCounts[i_svc]-1; i++) { test[i] = (ratios[i] > limit_ratio); } // end for (int i=last_i; i<last_i+stripVertexCounts[i_svc]*3; i+=3) last_i += stripVertexCounts[i_svc]; } // end for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) } else if (TEST == 1) { if (len < 2) return this; float[][] bs = new float[3][len-1]; float ALPHA1 = 1.0f + ALPHA; for (int i=0; i<len-1; i++) { bs[0][i] = ALPHA1 * rs[0][i] - ALPHA * rs[0][i+1]; bs[1][i] = ALPHA1 * rs[1][i] - ALPHA * rs[1][i+1]; bs[2][i] = ALPHA1 * rs[2][i] - ALPHA * rs[2][i+1]; } float[][] ds = coord_sys.toReference(bs); float IALPHA = 1.0f / ALPHA; last_i = 0; // start i for each vertex strip for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) { for (int i=last_i; i<last_i+stripVertexCounts[i_svc]-1; i++) { float a0 = cs[0][i+1] - cs[0][i]; float a1 = cs[1][i+1] - cs[1][i]; float a2 = cs[2][i+1] - cs[2][i]; float b0 = IALPHA * (cs[0][i] - ds[0][i]); float b1 = IALPHA * (cs[1][i] - ds[1][i]); float b2 = IALPHA * (cs[2][i] - ds[2][i]); float aa = (a0 * a0 + a1 * a1 + a2 * a2); float bb = (b0 * b0 + b1 * b1 + b2 * b2); float ab = (b0 * a0 + b1 * a1 + b2 * a2); // b = A projected onto B, as a signed fraction of B float b = ab / bb; // c = (norm(A projected onto B) / norm(A)) ^ 2 float c = (ab * ab) / (aa * bb); test[i] = !(0.5f < b && b < 2.0f && 0.5f < c); } // end for (int i=last_i; i<last_i+stripVertexCounts[i_svc]*3; i+=3) last_i += stripVertexCounts[i_svc]; } // end for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) } // end TEST == 1 cs = null; rs = null; float[] lastcoord = null; byte[] lastcol = null; VisADLineStripArray array = new VisADLineStripArray(); // 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; } // worst case makes as many strips as there were points int[] svcs = new int[coordinates.length]; int svc_index = 0; last_i = 0; // start i for each vertex strip int[] km = {0, 0}; j = 0; boolean any_split = false; for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) { int accum = 0; // strip counter j = color_length * last_i / 3; for (int i=last_i; i<last_i+stripVertexCounts[i_svc]*3; i+=3) { // first, add point at "i" float coord[] = new float[] {coordinates[i], coordinates[i+1], coordinates[i+2]}; byte[] col = null; if (color_length == 3) { col = new byte[] {colors[j], colors[j+1], colors[j+2]}; } else if (color_length == 4) { col = new byte[] {colors[j], colors[j+1], colors[j+2], colors[j+3]}; } accum++; if (accum == 1) { lastcoord = coord; lastcol = col; } else { nextPoint(accum, color_length, coords, cols, coord, col, lastcoord, lastcol, km); } if (i == last_i+stripVertexCounts[i_svc]*3-3) continue; // last point if (test[i/3]) { any_split = true; // treat split as a break if (accum >= 2) { svcs[svc_index] = accum; svc_index++; } accum = 0; // reset strip counter; } // end if split j += color_length; } // end for (int i=last_i; i<last_i+stripVertexCounts[i_svc]*3; i+=3) if (accum >= 2) { svcs[svc_index] = accum; svc_index++; } last_i += stripVertexCounts[i_svc]*3; } // end for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) if (!any_split) { return this; } else { array.vertexCount = km[0] / 3; array.coordinates = new float[km[0]]; System.arraycopy(coords, 0, array.coordinates, 0, km[0]); if (colors != null) { array.colors = new byte[km[1]]; System.arraycopy(cols, 0, array.colors, 0, km[1]); } array.stripVertexCounts = new int[svc_index]; System.arraycopy(svcs, 0, array.stripVertexCounts, 0, svc_index); return array; } } 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]; float[] lastcoord = null; byte[] lastcol = null; VisADLineStripArray array = new VisADLineStripArray(); // 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; } // 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[] km = {0, 0}; int j = 0; boolean any_split = false; for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) { int accum = 0; // strip counter j = color_length * last_i / 3; for (int i=last_i; i<last_i+stripVertexCounts[i_svc]*3; i+=3) { // first, add point at "i" float coord[] = new float[] {coordinates[i], coordinates[i+1], coordinates[i+2]}; byte[] col = null; if (color_length == 3) { col = new byte[] {colors[j], colors[j+1], colors[j+2]}; } else if (color_length == 4) { col = new byte[] {colors[j], colors[j+1], colors[j+2], colors[j+3]}; } accum++; if (accum == 1) { lastcoord = coord; lastcol = col; } else { nextPoint(accum, color_length, coords, cols, coord, col, lastcoord, lastcol, km); } if (i == last_i+stripVertexCounts[i_svc]*3-3) continue; // last point int i3 = i / 3; if ((lons[i3] < low && hi < lons[i3 + 1]) || (lons[i3 + 1] < low && hi < lons[i3])) { any_split = true; if (lon_axis < 0) { // not enough info to interpolate, so treat split as a break if (accum >= 2) { svcs[svc_index] = accum; svc_index++; } accum = 0; // reset strip counter; } else { // lon_axis >= 0 // split line by interpolation float a, b; float coord_first, coord_second; if (lons[i3] < low) { a = lons[i3] - bottom; b = top - lons[i3 + 1]; coord_first = coord_bottom; coord_second = coord_top; } else { a = top - lons[i3]; b = lons[i3 + 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; // create first point of split; coord = new float[] {alpha * coordinates[i] + beta * coordinates[i+3], alpha * coordinates[i+1] + beta * coordinates[i+4], alpha * coordinates[i+2] + beta * coordinates[i+5]}; coord[lon_axis] = coord_first; col = null; if (color_length == 3) { col = new byte[] {ShadowType.floatToByte( alpha * ShadowType.byteToFloat(colors[j]) + beta * ShadowType.byteToFloat(colors[j+3])), ShadowType.floatToByte( alpha * ShadowType.byteToFloat(colors[j+1]) + beta * ShadowType.byteToFloat(colors[j+4])), ShadowType.floatToByte( alpha * ShadowType.byteToFloat(colors[j+2]) + beta * ShadowType.byteToFloat(colors[j+5]))}; } else if (color_length == 4) { col = new byte[] {ShadowType.floatToByte( alpha * ShadowType.byteToFloat(colors[j]) + beta * ShadowType.byteToFloat(colors[j+4])), ShadowType.floatToByte( alpha * ShadowType.byteToFloat(colors[j+1]) + beta * ShadowType.byteToFloat(colors[j+5])), ShadowType.floatToByte( alpha * ShadowType.byteToFloat(colors[j+2]) + beta * ShadowType.byteToFloat(colors[j+6])), ShadowType.floatToByte( alpha * ShadowType.byteToFloat(colors[j+3]) + beta * ShadowType.byteToFloat(colors[j+7]))}; } accum++; if (accum == 1) { lastcoord = coord; lastcol = col; } else { nextPoint(accum, color_length, coords, cols, coord, col, lastcoord, lastcol, km); } // break strip between first and second points if (accum >= 2) { svcs[svc_index] = accum; svc_index++; } accum = 0; // reset strip counter; // create second point of split, identical to first except: coord[lon_axis] = coord_second; accum++; if (accum == 1) { lastcoord = coord; lastcol = col; } else { nextPoint(accum, color_length, coords, cols, coord, col, lastcoord, lastcol, km); } } // end if (lon_axis >= 0) } // end if split j += color_length; } // end for (int i=last_i; i<last_i+stripVertexCounts[i_svc]*3; i+=3) if (accum >= 2) { svcs[svc_index] = accum; svc_index++; } last_i += stripVertexCounts[i_svc]*3; } // end for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) if (!any_split) { return this; } else { array.vertexCount = km[0] / 3; array.coordinates = new float[km[0]]; System.arraycopy(coords, 0, array.coordinates, 0, km[0]); if (colors != null) { array.colors = new byte[km[1]]; System.arraycopy(cols, 0, array.colors, 0, km[1]); } array.stripVertexCounts = new int[svc_index]; System.arraycopy(svcs, 0, array.stripVertexCounts, 0, svc_index); return array; } } private void nextPoint(int accum, int color_length, float[] coords, byte[] cols, float[] coord, byte[] col, float[] lastcoord, byte[] lastcol, int[] km) { if (accum == 2) { coords[km[0]] = lastcoord[0]; coords[km[0]+1] = lastcoord[1]; coords[km[0]+2] = lastcoord[2]; km[0] += 3; if (colors != null) { cols[km[1]] = lastcol[0]; cols[km[1]+1] = lastcol[1]; cols[km[1]+2] = lastcol[2]; km[1] += 3; if (color_length == 4) { cols[km[1]++] = lastcol[3]; } } } // end if (accum == 2) coords[km[0]] = coord[0]; coords[km[0]+1] = coord[1]; coords[km[0]+2] = coord[2]; km[0] += 3; if (colors != null) { cols[km[1]] = col[0]; cols[km[1]+1] = col[1]; cols[km[1]+2] = col[2]; km[1] += 3; if (color_length == 4) { cols[km[1]++] = col[3]; } } } public VisADGeometryArray removeMissing() { VisADLineStripArray array = new VisADLineStripArray(); 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[] svcs = new int[coordinates.length / 4]; int svc_index = 0; int last_i = 0; // start i for each vertex strip int k = 0; int m = 0; int j = 0; boolean any_missing = false; for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) { int accum = 0; // strip counter j = color_length * last_i / 3; for (int i=last_i; i<last_i+stripVertexCounts[i_svc]*3; i+=3) { if (coordinates[i] == coordinates[i] && coordinates[i+1] == coordinates[i+1] && coordinates[i+2] == coordinates[i+2]) { accum++; if (accum >= 2) { int iml = i; int jml = j; if (accum == 2) { iml = i - 3; jml = j - color_length; } int jm = jml; for (int im=iml; im<=i; im+=3) { coords[k] = coordinates[im]; coords[k+1] = coordinates[im+1]; coords[k+2] = coordinates[im+2]; if (colors != null) { cols[m] = colors[jm]; cols[m+1] = colors[jm+1]; cols[m+2] = colors[jm+2]; m += 3; if (color_length == 4) { cols[m++] = colors[jm+3]; } } k += 3; jm += color_length; } // end for (im=iml; im<=i; im+=3) } // end if (accum >= 2) } else { // missing coordinates values any_missing = true; if (accum >= 2) { svcs[svc_index] = accum; svc_index++; } accum = 0; // reset strip counter; } j += color_length; } // end for (int i=last_i; i<last_i+stripVertexCounts[i_svc]*3; i+=3) if (accum >= 2) { svcs[svc_index] = accum; svc_index++; } last_i += stripVertexCounts[i_svc]*3; } // end for (int i_svc=0; i_svc<stripVertexCounts.length; i_svc++) if (!any_missing) { return this; } else { array.vertexCount = k / 3; 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); } array.stripVertexCounts = new int[svc_index]; System.arraycopy(svcs, 0, array.stripVertexCounts, 0, svc_index); return array; } } public Object clone() { VisADLineStripArray array = new VisADLineStripArray(); copy(array); if (stripVertexCounts != null) { array.stripVertexCounts = new int[stripVertexCounts.length]; System.arraycopy(stripVertexCounts, 0, array.stripVertexCounts, 0, stripVertexCounts.length); } return array; } }