//
// Contour2D.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;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import visad.util.Trace;
import visad.util.HersheyFont;
import java.awt.Font;
import java.text.DecimalFormat;
/**
* Contour2D is a class equipped with a 2-D contouring function.
* <P>
*/
public class Contour2D {
/** */
protected Contour2D con;
/** */
protected int whichlabels = 0;
/** */
protected boolean showgrid;
/** */
protected int rows, cols, scale;
/** */
protected int[] num1, num2, num3, num4;
/** */
protected float[][] vx1, vy1;
/** */
public static final int DIFFICULTY_THRESHOLD = 600000;
/** */
public static final float DIMENSION_THRESHOLD = 5.0E5f;
public static final byte SIDE_LEFT = 3;
public static final byte SIDE_RIGHT = 1;
public static final byte SIDE_TOP = 2;
public static final byte SIDE_BOTTOM = 0;
public static final byte SIDE_NONE = -1;
public static final byte CLOCKWISE = -1;
public static final byte CNTRCLOCKWISE = 1;
/**
* Compute contour lines for a 2-D array. If the interval is negative, then
* contour lines less than base will be drawn as dashed lines. The contour
* lines will be computed for all V such that:
*
* <pre>
* lowlimit <= V <= highlimit
* </pre>
*
* and
*
* <pre>
* V = base + n*interval for some integer n
* </pre>
*
* Note that the input array, g, should be in column-major (FORTRAN) order.
*
* @param g
* the 2-D array to contour.
* @param nr
* size of 2-D array in rows
* @param nc
* size of 2-D array in columns.
* @param interval
* contour interval
* @param lowlimit
* the lower limit on values to contour.
* @param highlimit
* the upper limit on values to contour.
* @param base
* base value to start contouring at.
* @param vx1
* array to put contour line vertices (x value)
* @param vy1
* array to put contour line vertices (y value)
* @param numv1
* pointer to int to return number of vertices in vx1,vy1
* @param auxValues
* colors corresponding to grid points
* @param swap
* @param fill
* true if filling contours
* @param grd_normals
* @param interval_colors
* @param lbl_vv
* values for label line segments
* @param lbl_cc
* label color triples
* @param lbl_loc
* center points for label locations
* @param scale_ratio
* @param label_size
* @param labelColor
* @param spatial_set
*
* @throws VisADException
*/
public static void contour(float g[], int nr, int nc, float interval,
float lowlimit, float highlimit, float base, float vx1[][],
float vy1[][], int[] numv1, byte[][] auxValues,
boolean[] swap, boolean fill, float[][][] grd_normals,
byte[][] interval_colors, float[][][][] lbl_vv,
byte[][][][] lbl_cc, float[][][] lbl_loc, double[] scale, double scale_ratio,
int label_freq, int label_line_skip,
double label_size, boolean labelAlign, byte[] labelColor,
Object labelFont, boolean sphericalDisplayCS,
Gridded3DSet spatial_set) throws VisADException {
boolean[] dashes = { false };
float[] intervals = intervalToLevels(interval, lowlimit, highlimit,
base, dashes);
boolean dash = dashes[0];
contour(g, nr, nc, intervals, lowlimit, highlimit, base, dash,
auxValues, swap, fill, grd_normals, interval_colors, scale,
scale_ratio, label_freq, label_line_skip,
label_size, labelAlign, labelColor, labelFont,
sphericalDisplayCS, spatial_set);
}
/**
* Returns an array of contour values and an indication on whether to use
* dashed lines below the base value.
*
* @param interval
* The contouring interval. Must be non-zero. If the interval is
* negative, then contour lines less than the base will be drawn
* as dashed lines. Must not be NaN.
* @param low
* The minimum contour value. The returned array will not contain
* a value below this. Must not be NaN.
* @param high
* The maximum contour value. The returned array will not contain
* a value above this. Must not be NaN.
* @param ba
* The base contour value. The returned values will be integer
* multiples of the interval away from this this value. Must not
* be NaN. dash Whether or not contour lines less than the base
* should be drawn as dashed lines. This is a computed and
* returned value.
* @param dash
*
* @return Levels array
* @throws VisADException
* The contour interval is zero or too small.
*/
public static float[] intervalToLevels(float interval, float low,
float high, float ba, boolean[] dash) throws VisADException {
float[] levs = null;
if (interval == 0.0) {
throw new VisADException("Contour interval cannot be zero");
}
dash[0] = false;
if (interval < 0) {
dash[0] = true;
interval = -interval;
}
// compute list of contours
// compute nlo and nhi, for low and high contour values in the box
long nlo = Math.round((Math.ceil((low - ba) / Math.abs(interval))));
long nhi = Math.round((Math.floor((high - ba) / Math.abs(interval))));
// how many contour lines are needed.
int numc = (int) (nhi - nlo) + 1;
if (numc < 1)
return levs;
if (numc > 4000) {
throw new VisADException("Contour interval " + interval
+ " too small for range " + low + "," + high);
}
try {
levs = new float[numc];
} catch (OutOfMemoryError e) {
throw new VisADException("Contour interval too small");
}
for (int i = 0; i < numc; i++) {
levs[i] = ba + (nlo + i) * interval;
}
return levs;
}
/** */
public static int vertexCnt = 0;
/** */
public static boolean TRUEVALUE = true;
public static ContourOutput contour(float g[], int nr, int nc,
float[] values, float lowlimit, float highlimit, float base,
boolean dash, byte[][] auxValues, boolean[] swap, boolean fill,
float[][][] grd_normals, byte[][] interval_colors, double[] scale,
double scale_ratio, int label_freq, int label_line_skip,
double label_size, boolean labelAlign,
byte[] labelColor, Object labelFont, boolean sphericalDisplayCS,
Gridded3DSet spatial_set) throws VisADException {
dash = fill ? false : dash;
int ir, ic;
int nrm, ncm;
int numc, il;
int lr, lc, lc2, lrr, lr2, lcc;
float xd, yd, xx, yy;
float xdd, ydd;
float gg;
// these are just estimates
// int est = 2 * Length; WLH 14 April 2000
double dest = Math.sqrt((double) spatial_set.getLength());
int est = (int) (dest * Math.sqrt(dest));
if (est < 1000)
est = 1000;
int maxsize = (2 * 2 * est) + est;
// setup colors arrays
int interval_length = (interval_colors.length > 0) ? interval_colors[0].length : 0;
// setup display coordinate arrays
float[] vx = new float[maxsize];
float[] vy = new float[maxsize];
int numv;
// JDM:Find the max and min values of the data
float maxValue = Float.NEGATIVE_INFINITY;
float minValue = Float.POSITIVE_INFINITY;
for (int i = 0; i < g.length; i++) {
if (g[i] > maxValue)
maxValue = g[i];
if (g[i] < minValue)
minValue = g[i];
}
/* DRM 1999-05-18, CTR 29 Jul 1999: values could be null */
float[] myvals = null;
boolean debug = false;
if (values != null && (minValue < maxValue) /* grid was not all missing */) {
myvals = (float[]) values.clone();
// Sort the values. Get the original indidices
int[] indices = QuickSort.sort(myvals);
// JDM: Now, change the order of the colors to reflect the new sort
// order
// BMF 2009-03-17: don't assume there are interval colors
byte[][] tmpColors = new byte[interval_colors.length][interval_length];
for (int colorIdx = 0; colorIdx < interval_length; colorIdx++) {
for (int rgbIdx = 0; rgbIdx < interval_colors.length; rgbIdx++) {
tmpColors[rgbIdx][indices[colorIdx]] = interval_colors[rgbIdx][colorIdx];
}
}
interval_colors = tmpColors;
// JDM: Clip the myvals array to only use values within the range of
// the
// data
int minIdx = 0;
int maxIdx = myvals.length - 1;
for (int i = 0; i < myvals.length; i++) {
if (minValue <= myvals[i]) {
break;
}
minIdx = i;
}
for (int i = myvals.length - 1; i >= 0; i--) {
if (maxValue >= myvals[i]) {
break;
}
maxIdx = i;
}
// debug =true;
int newSize = maxIdx - minIdx + 1;
int newIdx = 0;
if (debug) {
System.err.println("min: " + minValue + " max:" + maxValue
+ " idx:" + minIdx + "-" + maxIdx + " new size:"
+ newSize);
System.err.print("original values: ");
for (int i = 0; i < myvals.length; i++) {
System.err.print(myvals[i] + ",");
}
System.err.println("");
}
float[] tmpValues = new float[newSize];
tmpColors = new byte[interval_colors.length][newSize];
for (int i = minIdx; i <= maxIdx; i++) {
for (int rgbIdx = 0; rgbIdx < interval_colors.length; rgbIdx++) {
tmpColors[rgbIdx][newIdx] = interval_colors[rgbIdx][i];
}
tmpValues[newIdx] = myvals[i];
newIdx++;
}
if (debug) {
System.err.print("new values: ");
for (int i = 0; i < tmpValues.length; i++) {
System.err.print(tmpValues[i] + ",");
}
System.err.println("");
}
myvals = tmpValues;
interval_colors = tmpColors;
}
int low;
int hi;
int t;
byte[][] auxLevels = null;
int naux = (auxValues != null) ? auxValues.length : 0;
byte[] auxa = null;
byte[] auxb = null;
byte[] auxc = null;
byte[] auxd = null;
if (naux > 0) {
for (int i = 0; i < naux; i++) {
if (auxValues[i].length != g.length) {
throw new SetException("Contour2D.contour: "
+ "auxValues lengths don't match");
}
}
auxa = new byte[naux];
auxb = new byte[naux];
auxc = new byte[naux];
auxd = new byte[naux];
auxLevels = new byte[naux][maxsize];
}
if (values == null)
return null; // WLH 24 Aug 99
// JDM: if we have no values then return
if (myvals == null || myvals.length == 0)
return null;
// flags for each level indicating dashed rendering
boolean[] dashFlags = new boolean[myvals.length];
int numLevels = myvals.length;
float minLevelValue = myvals[0];
float maxLevelValue = myvals[numLevels - 1];
/*
* DRM: 1999-05-19 - Not needed since dash is a boolean // check for bad
* contour interval if (interval==0.0) { throw new
* DisplayException("Contour2D.contour: interval cannot be 0"); } if
* (!dash) { // draw negative contour lines as dashed lines interval =
* -interval; idash = 1; } else { idash = 0; }
*/
nrm = nr - 1;
ncm = nc - 1;
xdd = ((nr - 1) - 0.0f) / (nr - 1.0f); // = 1.0
ydd = ((nc - 1) - 0.0f) / (nc - 1.0f); // = 1.0
/**
* -TDR xd = xdd - 0.0001f; yd = ydd - 0.0001f; gap too big *
*/
xd = xdd - 0.00002f;
yd = ydd - 0.00002f;
/*
* set up mark array mark= 0 if avail for label center, 2 if in label,
* and 1 if not available and not in label
*
* lr and lc give label size in grid boxes lrr and lcc give unavailable
* radius
*/
if (swap[0]) {
lr = 1 + (nr - 2) / 10;
lc = 1 + (nc - 2) / 50;
} else {
lr = 1 + (nr - 2) / 50;
lc = 1 + (nc - 2) / 10;
}
lc2 = lc / 2;
lr2 = lr / 2;
lrr = 1 + (nr - 2) / 8;
lcc = 1 + (nc - 2) / 8;
// allocate mark array
char[] mark = new char[nr * nc];
// set top and bottom rows to 1
float max_g = -Float.MAX_VALUE;
float min_g = Float.MAX_VALUE;
for (ic = 0; ic < nc; ic++) {
for (ir = 0; ir < lr; ir++) {
mark[(ic) * nr + (ir)] = 1;
mark[(ic) * nr + (nr - ir - 2)] = 1;
float val = g[(ic) * nr + (ir)];
if (val > max_g)
max_g = val;
if (val < min_g)
min_g = val;
}
}
// set left and right columns to 1
for (ir = 0; ir < nr; ir++) {
for (ic = 0; ic < lc; ic++) {
mark[(ic) * nr + (ir)] = 1;
mark[(nc - ic - 2) * nr + (ir)] = 1;
}
}
numv = 0;
// - color fill arrays
byte[][] color_bin = null;
byte[][][] o_flags = null;
short[][] n_lines = null;
short[][] ctrLow = null;
if (fill) {
color_bin = interval_colors;
o_flags = new byte[nrm][ncm][];
n_lines = new short[nrm][ncm];
ctrLow = new short[nrm][ncm];
}
ContourStripSet ctrSet = new ContourStripSet(myvals, swap,
scale_ratio, label_freq, label_line_skip, label_size, nr, nc, spatial_set);
visad.util.Trace.call1("Contour2d.loop", " nrm=" + nrm + " ncm=" + ncm
+ " naux=" + naux + " myvals.length=" + myvals.length);
// compute contours
for (ic = 0; ic < ncm; ic++) {
int ic_plus1 = ic + 1;
yy = ydd * ic + 0.0f; // = ic
for (ir = 0; ir < nrm; ir++) {
int ir_plus1 = ir + 1;
xx = xdd * ir + 0.0f; // = ir
int ic_times_nr = ic * nr;
int ic_plus1_times_nr = ic_plus1 * nr;
float ga, gb, gc, gd;
float gAvg, gMin, gMax;
float tmp1, tmp2;
// WLH 21 April 2000
// if (numv+8 >= maxsize || nump+4 >= 2*maxsize) {
if (numv + 8 >= maxsize) {
// allocate more space
maxsize = 2 * maxsize;
/*
* WLH 21 April 2000 int[] tt = ipnt; ipnt = new int[2
* maxsize]; System.arraycopy(tt, 0, ipnt, 0, nump);
*/
float[] tx = vx;
float[] ty = vy;
vx = new float[maxsize];
vy = new float[maxsize];
System.arraycopy(tx, 0, vx, 0, numv);
System.arraycopy(ty, 0, vy, 0, numv);
tx = null;
ty = null;
if (naux > 0) {
byte[][] ta = auxLevels;
auxLevels = new byte[naux][maxsize];
for (int i = 0; i < naux; i++) {
System.arraycopy(ta[i], 0, auxLevels[i], 0, numv);
}
ta = null;
}
}
// save index of first vertex in this grid box
// JDM: ipnt[nump++] = numv;
/*
* ga = ( g[ (ic) nr + (ir) ] ); gb = ( g[ (ic) nr + (ir+1) ] );
* gc = ( g[ (ic+1) nr + (ir) ] ); gd = ( g[ (ic+1) nr + (ir+1)
* ] ); boolean miss = false; if (ga != ga || gb != gb || gc !=
* gc || gd != gd) { miss = true; System.out.println("ic, ir = "
* + ic + " " + ir + " gabcd = " + ga + " " + gb + " " + gc +
* " " + gd); }
*/
/*
* if (ga != ga || gb != gb || gc != gc || gd != gd) { if
* (!anymissing) { anymissing = true;
* System.out.println("missing"); } } else { if (!anynotmissing)
* { anynotmissing = true; System.out.println("notmissing"); } }
*/
// get 4 corner values, skip box if any are missing
//
// [c, (x,y+ydd)]-------[d, (x+xdd,y+ydd)]
// | |
// | |
// | |
// [a, (x,y)]------------[b, (x+xdd,y)]
//
// ------------------------------
ga = g[ic_times_nr + ir];
if (Float.isNaN(ga))
continue;
gb = g[ic_times_nr + ir_plus1];
if (Float.isNaN(gb))
continue;
gc = g[ic_plus1_times_nr + ir];
if (Float.isNaN(gc))
continue;
gd = g[ic_plus1_times_nr + ir_plus1];
if (Float.isNaN(gd))
continue;
/*
* DRM move outside the loop byte[] auxa = null; byte[] auxb =
* null; byte[] auxc = null; byte[] auxd = null; if (naux > 0) {
* auxa = new byte[naux]; auxb = new byte[naux]; auxc = new
* byte[naux]; auxd = new byte[naux];
*/
if (naux > 0) {
for (int i = 0; i < naux; i++) {
byte[] auxValues_i = auxValues[i];
auxa[i] = auxValues_i[ic_times_nr + ir];
auxb[i] = auxValues_i[ic_times_nr + ir_plus1];
auxc[i] = auxValues_i[ic_plus1_times_nr + ir];
auxd[i] = auxValues_i[ic_plus1_times_nr + ir_plus1];
}
}
// find average, min, and max of 4 corner values
gAvg = (ga + gb + gc + gd) / 4.0f;
// gMin = MIN4(ga,gb,gc,gd);
tmp1 = ((ga) < (gb) ? (ga) : (gb));
tmp2 = ((gc) < (gd) ? (gc) : (gd));
gMin = ((tmp1) < (tmp2) ? (tmp1) : (tmp2));
// gMax = MAX4(ga,gb,gc,gd);
tmp1 = ((ga) > (gb) ? (ga) : (gb));
tmp2 = ((gc) > (gd) ? (gc) : (gd));
gMax = ((tmp1) > (tmp2) ? (tmp1) : (tmp2));
/*
* remove for new signature, replace with code below // compute
* clow and chi, low and high contour values in the box tmp1 =
* (gMin-base) / interval; clow = base + interval (( (tmp1) >= 0
* ? (int) ((tmp1) + 0.5) : (int) ((tmp1)-0.5) )-1); while
* (clow<gMin) { clow += interval; }
*
* tmp1 = (gMax-base) / interval; chi = base + interval ((
* (tmp1) >= 0 ? (int) ((tmp1) + 0.5) : (int) ((tmp1)-0.5) )+1);
* while (chi>gMax) { chi -= interval; }
*
* // how many contour lines in the box: tmp1 = (chi-clow) /
* interval; numc = 1+( (tmp1) >= 0 ? (int) ((tmp1) + 0.5) :
* (int) ((tmp1)-0.5) );
*
* // gg is current contour line value gg = clow;
*/
low = 0;
hi = numLevels - 1;
if (gMax < minLevelValue || gMin > maxLevelValue) {
// no contours
numc = 1;
} else {
// some inside the box
// JDM: Instead of iterating through the whole list just do
// a
// binarySearch
/*
* for (int i = 0; i < myvals.length; i++) { if (i == 0 &&
* myvals[i] >= gn) { low = i; } else if (myvals[i] >= gn &&
* myvals[i-1] < gn) { low = i; } if (i == 0 && myvals[i] >=
* gx) { hi = i; } else if (myvals[i] >= gx && myvals[i-1] <
* gx) { hi = i; } }
*/
hi = java.util.Arrays.binarySearch(myvals, gMax);
if (hi < 0)
hi = (-hi) - 1;
if (hi >= myvals.length)
hi = myvals.length - 1;
low = java.util.Arrays.binarySearch(myvals, gMin);
if (low < 0)
low = (-low) - 1;
numc = hi - low + 1;
}
// gg = myvals[low];
/*
* if (!any && numc > 0) { System.out.println("gMin = " + gMin +
* " gMax = " + gMax + " gAvg = " + gAvg);
* System.out.println("numc = " + numc + " clow = " +
* myvals[low] + " chi = " + myvals[hi]); any = true; }
*/
if (fill) {
o_flags[ir][ic] = new byte[2 * numc]; // - case flags
n_lines[ir][ic] = 0; // - number of contour line segments
ctrLow[ir][ic] = (short) hi;
}
for (il = 0; il < numc; il++) {
if ((low + il) >= myvals.length) {
System.err.println("bad range: myvals.length=" + myvals
+ " il=" + il + " low=" + low + " high=" + hi);
}
gg = myvals[low + il];
// WLH 21 April 2000
// if (numv+8 >= maxsize || nump+4 >= 2*maxsize) {
if (numv + 8 >= maxsize) {
// allocate more space
maxsize = 2 * maxsize;
/*
* WLH 21 April 2000 int[] tt = ipnt; ipnt = new int[2
* maxsize]; System.arraycopy(tt, 0, ipnt, 0, nump);
*/
float[] tx = vx;
float[] ty = vy;
vx = new float[maxsize];
vy = new float[maxsize];
System.arraycopy(tx, 0, vx, 0, numv);
System.arraycopy(ty, 0, vy, 0, numv);
tx = null;
ty = null;
if (naux > 0) {
byte[][] ta = auxLevels;
auxLevels = new byte[naux][maxsize];
for (int i = 0; i < naux; i++) {
System.arraycopy(ta[i], 0, auxLevels[i], 0,
numv);
}
ta = null;
}
}
// make sure gg is within contouring limits
if (gg < gMin)
continue;
if (gg > gMax)
break;
if (gg < lowlimit)
continue;
if (gg > highlimit)
break;
// compute orientation of lines inside box
int ii = 0;
if (gg > ga)
ii = 1;
if (gg > gb)
ii += 2;
if (gg > gc)
ii += 4;
if (gg > gd)
ii += 8;
if (ii > 7)
ii = 15 - ii;
if (ii <= 0)
continue;
if (fill) {
if ((low + il) < ctrLow[ir][ic])
ctrLow[ir][ic] = (short) (low + il);
}
// DO LABEL HERE
if ((mark[(ic) * nr + (ir)]) == 0) {
int kc, kr, mc, mr, jc, jr;
// Insert a label
// BOX TO AVOID
kc = ic - lc2 - lcc;
kr = ir - lr2 - lrr;
mc = kc + 2 * lcc + lc - 1;
mr = kr + 2 * lrr + lr - 1;
// OK here
for (jc = kc; jc <= mc; jc++) {
if (jc >= 0 && jc < nc) {
for (jr = kr; jr <= mr; jr++) {
if (jr >= 0 && jr < nr) {
if ((mark[(jc) * nr + (jr)]) != 2) {
mark[(jc) * nr + (jr)] = 1;
}
}
}
}
}
// BOX TO HOLD LABEL
kc = ic - lc2;
kr = ir - lr2;
mc = kc + lc - 1;
mr = kr + lr - 1;
for (jc = kc; jc <= mc; jc++) {
if (jc >= 0 && jc < nc) {
for (jr = kr; jr <= mr; jr++) {
if (jr >= 0 && jr < nr) {
mark[(jc) * nr + (jr)] = 2;
}
}
}
}
}
float gba, gca, gdb, gdc;
switch (ii) {
case 1:
gba = gb - ga;
gca = gc - ga;
if (naux > 0) {
float ratioba = (gg - ga) / gba;
float ratioca = (gg - ga) / gca;
for (int i = 0; i < naux; i++) {
t = (int) ((1.0f - ratioba)
* ((auxa[i] < 0) ? ((float) auxa[i]) + 256.0f
: ((float) auxa[i])) + ratioba
* ((auxb[i] < 0) ? ((float) auxb[i]) + 256.0f
: ((float) auxb[i])));
auxLevels[i][numv] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
t = (int) ((1.0f - ratioca)
* ((auxa[i] < 0) ? ((float) auxa[i]) + 256.0f
: ((float) auxa[i])) + ratioca
* ((auxc[i] < 0) ? ((float) auxc[i]) + 256.0f
: ((float) auxc[i])));
auxLevels[i][numv + 1] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
/*
* MEM_WLH auxLevels[i][numv] = auxa[i] +
* (auxb[i]-auxa[i]) ratioba;
* auxLevels[i][numv+1] = auxa[i] +
* (auxc[i]-auxa[i]) ratioca;
*/
}
}
if (((gba) < 0 ? -(gba) : (gba)) < 0.0000001) {
vx[numv] = xx;
} else {
vx[numv] = xx + xd * (gg - ga) / gba;
}
vy[numv] = yy;
numv++;
if (((gca) < 0 ? -(gca) : (gca)) < 0.0000001) {
vy[numv] = yy;
} else {
vy[numv] = yy + yd * (gg - ga) / gca;
}
vx[numv] = xx;
numv++;
if (fill) {
o_flags[ir][ic][n_lines[ir][ic]] = (byte) ii;
n_lines[ir][ic]++;
}
if (vx[numv - 2] == vx[numv - 1]
|| vy[numv - 2] == vy[numv - 1]) {
vx[numv - 2] += 0.00001f;
vy[numv - 1] += 0.00001f;
}
break;
case 2:
gba = gb - ga;
gdb = gd - gb;
if (naux > 0) {
float ratioba = (gg - ga) / gba;
float ratiodb = (gg - gb) / gdb;
for (int i = 0; i < naux; i++) {
t = (int) ((1.0f - ratioba)
* ((auxa[i] < 0) ? ((float) auxa[i]) + 256.0f
: ((float) auxa[i])) + ratioba
* ((auxb[i] < 0) ? ((float) auxb[i]) + 256.0f
: ((float) auxb[i])));
auxLevels[i][numv] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
t = (int) ((1.0f - ratiodb)
* ((auxb[i] < 0) ? ((float) auxb[i]) + 256.0f
: ((float) auxb[i])) + ratiodb
* ((auxd[i] < 0) ? ((float) auxd[i]) + 256.0f
: ((float) auxd[i])));
auxLevels[i][numv + 1] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
/*
* MEM_WLH auxLevels[i][numv] = auxa[i] +
* (auxb[i]-auxa[i]) ratioba;
* auxLevels[i][numv+1] = auxb[i] +
* (auxd[i]-auxb[i]) ratiodb;
*/
}
}
if (((gba) < 0 ? -(gba) : (gba)) < 0.0000001)
vx[numv] = xx;
else
vx[numv] = xx + xd * (gg - ga) / gba;
vy[numv] = yy;
numv++;
if (((gdb) < 0 ? -(gdb) : (gdb)) < 0.0000001)
vy[numv] = yy;
else
vy[numv] = yy + yd * (gg - gb) / gdb;
vx[numv] = xx + xd;
numv++;
if (fill) {
o_flags[ir][ic][n_lines[ir][ic]] = (byte) ii;
n_lines[ir][ic]++;
}
if (vx[numv - 2] == vx[numv - 1]
|| vy[numv - 2] == vy[numv - 1]) {
vx[numv - 2] -= 0.00001f;
vy[numv - 1] += 0.00001f;
}
break;
case 3:
gca = gc - ga;
gdb = gd - gb;
if (naux > 0) {
float ratioca = (gg - ga) / gca;
float ratiodb = (gg - gb) / gdb;
for (int i = 0; i < naux; i++) {
t = (int) ((1.0f - ratioca)
* ((auxa[i] < 0) ? ((float) auxa[i]) + 256.0f
: ((float) auxa[i])) + ratioca
* ((auxc[i] < 0) ? ((float) auxc[i]) + 256.0f
: ((float) auxc[i])));
auxLevels[i][numv] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
t = (int) ((1.0f - ratiodb)
* ((auxb[i] < 0) ? ((float) auxb[i]) + 256.0f
: ((float) auxb[i])) + ratiodb
* ((auxd[i] < 0) ? ((float) auxd[i]) + 256.0f
: ((float) auxd[i])));
auxLevels[i][numv + 1] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
/*
* MEM_WLH auxLevels[i][numv] = auxa[i] +
* (auxc[i]-auxa[i]) ratioca;
* auxLevels[i][numv+1] = auxb[i] +
* (auxd[i]-auxb[i]) ratiodb;
*/
}
}
if (((gca) < 0 ? -(gca) : (gca)) < 0.0000001)
vy[numv] = yy;
else
vy[numv] = yy + yd * (gg - ga) / gca;
vx[numv] = xx;
numv++;
if (((gdb) < 0 ? -(gdb) : (gdb)) < 0.0000001)
vy[numv] = yy;
else
vy[numv] = yy + yd * (gg - gb) / gdb;
vx[numv] = xx + xd;
numv++;
if (fill) {
o_flags[ir][ic][n_lines[ir][ic]] = (byte) ii;
n_lines[ir][ic]++;
}
break;
case 4:
gca = gc - ga;
gdc = gd - gc;
if (naux > 0) {
float ratioca = (gg - ga) / gca;
float ratiodc = (gg - gc) / gdc;
for (int i = 0; i < naux; i++) {
t = (int) ((1.0f - ratioca)
* ((auxa[i] < 0) ? ((float) auxa[i]) + 256.0f
: ((float) auxa[i])) + ratioca
* ((auxc[i] < 0) ? ((float) auxc[i]) + 256.0f
: ((float) auxc[i])));
auxLevels[i][numv] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
t = (int) ((1.0f - ratiodc)
* ((auxc[i] < 0) ? ((float) auxc[i]) + 256.0f
: ((float) auxc[i])) + ratiodc
* ((auxd[i] < 0) ? ((float) auxd[i]) + 256.0f
: ((float) auxd[i])));
auxLevels[i][numv + 1] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
/*
* MEM_WLH auxLevels[i][numv] = auxa[i] +
* (auxc[i]-auxa[i]) ratioca;
* auxLevels[i][numv+1] = auxc[i] +
* (auxd[i]-auxc[i]) ratiodc;
*/
}
}
if (((gca) < 0 ? -(gca) : (gca)) < 0.0000001)
vy[numv] = yy;
else
vy[numv] = yy + yd * (gg - ga) / gca;
vx[numv] = xx;
numv++;
if (((gdc) < 0 ? -(gdc) : (gdc)) < 0.0000001)
vx[numv] = xx;
else
vx[numv] = xx + xd * (gg - gc) / gdc;
vy[numv] = yy + yd;
numv++;
if (fill) {
o_flags[ir][ic][n_lines[ir][ic]] = (byte) ii;
n_lines[ir][ic]++;
}
if (vx[numv - 2] == vx[numv - 1]
|| vy[numv - 2] == vy[numv - 1]) {
vx[numv - 1] += 0.00001f;
vy[numv - 2] -= 0.00001f;
}
break;
case 5:
gba = gb - ga;
gdc = gd - gc;
if (naux > 0) {
float ratioba = (gg - ga) / gba;
float ratiodc = (gg - gc) / gdc;
for (int i = 0; i < naux; i++) {
t = (int) ((1.0f - ratioba)
* ((auxa[i] < 0) ? ((float) auxa[i]) + 256.0f
: ((float) auxa[i])) + ratioba
* ((auxb[i] < 0) ? ((float) auxb[i]) + 256.0f
: ((float) auxb[i])));
auxLevels[i][numv] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
t = (int) ((1.0f - ratiodc)
* ((auxc[i] < 0) ? ((float) auxc[i]) + 256.0f
: ((float) auxc[i])) + ratiodc
* ((auxd[i] < 0) ? ((float) auxd[i]) + 256.0f
: ((float) auxd[i])));
auxLevels[i][numv + 1] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
/*
* MEM_WLH auxLevels[i][numv] = auxa[i] +
* (auxb[i]-auxa[i]) ratioba;
* auxLevels[i][numv+1] = auxc[i] +
* (auxd[i]-auxc[i]) ratiodc;
*/
}
}
if (((gba) < 0 ? -(gba) : (gba)) < 0.0000001)
vx[numv] = xx;
else
vx[numv] = xx + xd * (gg - ga) / gba;
vy[numv] = yy;
numv++;
if (((gdc) < 0 ? -(gdc) : (gdc)) < 0.0000001)
vx[numv] = xx;
else
vx[numv] = xx + xd * (gg - gc) / gdc;
vy[numv] = yy + yd;
numv++;
if (fill) {
o_flags[ir][ic][n_lines[ir][ic]] = (byte) ii;
n_lines[ir][ic]++;
}
break;
case 6:
gba = gb - ga;
gdc = gd - gc;
gca = gc - ga;
gdb = gd - gb;
if (naux > 0) {
float ratioba = (gg - ga) / gba;
float ratiodc = (gg - gc) / gdc;
float ratioca = (gg - ga) / gca;
float ratiodb = (gg - gb) / gdb;
for (int i = 0; i < naux; i++) {
t = (int) ((1.0f - ratioba)
* ((auxa[i] < 0) ? ((float) auxa[i]) + 256.0f
: ((float) auxa[i])) + ratioba
* ((auxb[i] < 0) ? ((float) auxb[i]) + 256.0f
: ((float) auxb[i])));
auxLevels[i][numv] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
/*
* MEM_WLH auxLevels[i][numv] = auxa[i] +
* (auxb[i]-auxa[i]) ratioba;
*/
if ((gg > gAvg) ^ (ga < gb)) {
t = (int) ((1.0f - ratioca)
* ((auxa[i] < 0) ? ((float) auxa[i]) + 256.0f
: ((float) auxa[i])) + ratioca
* ((auxc[i] < 0) ? ((float) auxc[i]) + 256.0f
: ((float) auxc[i])));
auxLevels[i][numv + 1] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
t = (int) ((1.0f - ratiodb)
* ((auxb[i] < 0) ? ((float) auxb[i]) + 256.0f
: ((float) auxb[i])) + ratiodb
* ((auxd[i] < 0) ? ((float) auxd[i]) + 256.0f
: ((float) auxd[i])));
auxLevels[i][numv + 2] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
/*
* MEM_WLH auxLevels[i][numv+1] = auxa[i] +
* (auxc[i]-auxa[i]) ratioca;
* auxLevels[i][numv+2] = auxb[i] +
* (auxd[i]-auxb[i]) ratiodb;
*/
} else {
t = (int) ((1.0f - ratiodb)
* ((auxb[i] < 0) ? ((float) auxb[i]) + 256.0f
: ((float) auxb[i])) + ratiodb
* ((auxd[i] < 0) ? ((float) auxd[i]) + 256.0f
: ((float) auxd[i])));
auxLevels[i][numv + 1] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
t = (int) ((1.0f - ratioca)
* ((auxa[i] < 0) ? ((float) auxa[i]) + 256.0f
: ((float) auxa[i])) + ratioca
* ((auxc[i] < 0) ? ((float) auxc[i]) + 256.0f
: ((float) auxc[i])));
auxLevels[i][numv + 2] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
/*
* MEM_WLH auxLevels[i][numv+1] = auxb[i] +
* (auxd[i]-auxb[i]) ratiodb;
* auxLevels[i][numv+2] = auxa[i] +
* (auxc[i]-auxa[i]) ratioca;
*/
}
t = (int) ((1.0f - ratiodc)
* ((auxc[i] < 0) ? ((float) auxc[i]) + 256.0f
: ((float) auxc[i])) + ratiodc
* ((auxd[i] < 0) ? ((float) auxd[i]) + 256.0f
: ((float) auxd[i])));
auxLevels[i][numv + 3] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
/*
* MEM_WLH auxLevels[i][numv+3] = auxc[i] +
* (auxd[i]-auxc[i]) ratiodc;
*/
}
}
if (((gba) < 0 ? -(gba) : (gba)) < 0.0000001)
vx[numv] = xx;
else
vx[numv] = xx + xd * (gg - ga) / gba;
vy[numv] = yy;
numv++;
// here's a brain teaser
if ((gg > gAvg) ^ (ga < gb)) { // (XOR)
if (((gca) < 0 ? -(gca) : (gca)) < 0.0000001)
vy[numv] = yy;
else
vy[numv] = yy + yd * (gg - ga) / gca;
vx[numv] = xx;
numv++;
if (fill) {
o_flags[ir][ic][n_lines[ir][ic]] = (byte) 1
+ (byte) 32;
n_lines[ir][ic]++;
}
if (((gdb) < 0 ? -(gdb) : (gdb)) < 0.0000001)
vy[numv] = yy;
else
vy[numv] = yy + yd * (gg - gb) / gdb;
vx[numv] = xx + xd;
if (fill) {
o_flags[ir][ic][n_lines[ir][ic]] = (byte) 7
+ (byte) 32;
n_lines[ir][ic]++;
}
numv++;
} else {
if (((gdb) < 0 ? -(gdb) : (gdb)) < 0.0000001)
vy[numv] = yy;
else
vy[numv] = yy + yd * (gg - gb) / gdb;
vx[numv] = xx + xd;
numv++;
if (fill) {
o_flags[ir][ic][n_lines[ir][ic]] = (byte) 2
+ (byte) 32;
n_lines[ir][ic]++;
}
if (((gca) < 0 ? -(gca) : (gca)) < 0.0000001)
vy[numv] = yy;
else
vy[numv] = yy + yd * (gg - ga) / gca;
vx[numv] = xx;
numv++;
if (fill) {
o_flags[ir][ic][n_lines[ir][ic]] = (byte) 4
+ (byte) 32;
n_lines[ir][ic]++;
}
}
if (((gdc) < 0 ? -(gdc) : (gdc)) < 0.0000001)
vx[numv] = xx;
else
vx[numv] = xx + xd * (gg - gc) / gdc;
vy[numv] = yy + yd;
numv++;
break;
case 7:
gdb = gd - gb;
gdc = gd - gc;
if (naux > 0) {
float ratiodb = (gg - gb) / gdb;
float ratiodc = (gg - gc) / gdc;
for (int i = 0; i < naux; i++) {
t = (int) ((1.0f - ratiodb)
* ((auxb[i] < 0) ? ((float) auxb[i]) + 256.0f
: ((float) auxb[i])) + ratiodb
* ((auxd[i] < 0) ? ((float) auxd[i]) + 256.0f
: ((float) auxd[i])));
auxLevels[i][numv] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
t = (int) ((1.0f - ratiodc)
* ((auxc[i] < 0) ? ((float) auxc[i]) + 256.0f
: ((float) auxc[i])) + ratiodc
* ((auxd[i] < 0) ? ((float) auxd[i]) + 256.0f
: ((float) auxd[i])));
auxLevels[i][numv + 1] = (byte) ((t < 0) ? 0
: ((t > 255) ? -1 : ((t < 128) ? t
: t - 256)));
/*
* MEM_WLH auxLevels[i][numv] = auxb[i] +
* (auxb[i]-auxb[i]) ratiodb;
* auxLevels[i][numv+1] = auxc[i] +
* (auxd[i]-auxc[i]) ratiodc;
*/
}
}
if (((gdb) < 0 ? -(gdb) : (gdb)) < 0.0000001)
vy[numv] = yy;
else
vy[numv] = yy + yd * (gg - gb) / gdb;
vx[numv] = xx + xd;
numv++;
if (((gdc) < 0 ? -(gdc) : (gdc)) < 0.0000001)
vx[numv] = xx;
else
vx[numv] = xx + xd * (gg - gc) / gdc;
vy[numv] = yy + yd;
numv++;
if (fill) {
o_flags[ir][ic][n_lines[ir][ic]] = (byte) ii;
n_lines[ir][ic]++;
}
if (vx[numv - 2] == vx[numv - 1]
|| vy[numv - 2] == vy[numv - 1]) {
vx[numv - 1] -= 0.00001f;
vy[numv - 2] -= 0.00001f;
}
break;
} // switch
// If contour level is negative, make dashed line
if (gg < base && dash) { /* DRM: 1999-05-19 */
dashFlags[low + il] = true;
}
/*
* if ((20.0 <= vy[numv-2] && vy[numv-2] < 22.0) || (20.0 <=
* vy[numv-1] && vy[numv-1] < 22.0)) {
* System.out.println("vy = " + vy[numv-1] + " " +
* vy[numv-2] + " ic, ir = " + ic + " " + ir); }
*/
if (ii == 6) { // - add last two pairs
ctrSet.add(vx, vy, numv - 4, numv - 3, low + il);
ctrSet.add(vx, vy, numv - 2, numv - 1, low + il);
} else {
ctrSet.add(vx, vy, numv - 2, numv - 1, low + il);
}
} // for il -- NOTE: gg incremented in for statement
} // for ic
} // for ir
// System.err.println ("ii:" + ii1 + " " +ii2 + " " +ii3 + " " +ii4 +
// " "
// +ii5 + " " +ii6);
visad.util.Trace.call2("Contour2d.loop");
/** ------------------- Color Fill ------------------------- */
TriangleStripBuilder triStripBldr = null;
if (fill) {
triStripBldr = new TriangleStripBuilder(ncm, nrm, color_bin.length);
fillGridBox(g, n_lines, vx, vy, xd, xdd, yd, ydd, nr, nrm, nc, ncm,
ctrLow, o_flags, myvals, color_bin, grd_normals,
triStripBldr);
// BMF 2006-10-04 do not return, ie. draw labels on filled contours
// for now, just return because we don't need to do labels
// return;
}
// ---TDR, build Contour Strips
Trace.call1("Contour2d.getLineColorArrays");
ctrSet.getLineColorArrays(vx, vy, auxLevels, labelColor, labelFont,
labelAlign, sphericalDisplayCS, dashFlags);
Trace.call2("Contour2d.getLineColorArrays");
return new ContourOutput(ctrSet, triStripBldr);
}
/**
*
* @param g
* @param n_lines
* @param vx
* @param vy
* @param xd
* @param xdd
* @param yd
* @param ydd
* @param nr
* @param nrm
* @param nc
* @param ncm
* @param ctrLow
* @param o_flags
* @param values
* @param color_bin
* @param grd_normals
* @param triStripBldr
*/
private static void fillGridBox(float[] g, short[][] n_lines, float[] vx,
float[] vy, float xd, float xdd, float yd, float ydd, int nr,
int nrm, int nc, int ncm, short[][] ctrLow, byte[][][] o_flags,
float[] values, byte[][] color_bin, float[][][] grd_normals,
TriangleStripBuilder triStripBldr) {
float xx, yy;
int[] numv = new int[1];
numv[0] = 0;
for (int ic = 0; ic < ncm; ic++) {
yy = ydd * ic + 0.0f;
for (int ir = 0; ir < nrm; ir++) {
triStripBldr.setGridBox(ic, ir);
float ga, gb, gc, gd;
xx = xdd * ir + 0.0f;
// get 4 corner values, skip box if any are missing
ga = (g[(ic) * nr + (ir)]);
// test for missing
if (Float.isNaN(ga))
continue;
gb = (g[(ic) * nr + (ir + 1)]);
// test for missing
if (Float.isNaN(gb))
continue;
gc = (g[(ic + 1) * nr + (ir)]);
// test for missing
if (Float.isNaN(gc))
continue;
gd = (g[(ic + 1) * nr + (ir + 1)]);
// test for missing
if (Float.isNaN(gd ))
continue;
numv[0] += n_lines[ir][ic] * 2;
fillGridBox(new float[] { ga, gb, gc, gd }, n_lines[ir][ic],
vx, vy, xx, yy, xd, yd, ic, ir, ctrLow[ir][ic],
numv[0], o_flags[ir][ic], values, color_bin,
grd_normals, triStripBldr);
}
}
}
/**
*
* @param corners
* @param numc
* @param vx
* @param vy
* @param xx
* @param yy
* @param xd
* @param yd
* @param nc
* @param nr
* @param ctrLow
* @param numv
* @param o_flags
* @param values
* @param color_bin
* @param grd_normals
* @param triStripBldr
*/
private static void fillGridBox(float[] corners, int numc, float[] vx,
float[] vy, float xx, float yy, float xd, float yd, int nc, int nr,
short ctrLow, int numv, byte[] o_flags, float[] values,
byte[][] color_bin, float[][][] grd_normals,
TriangleStripBuilder triStripBldr) {
int il = 0;
int color_length = color_bin.length;
float[] vv1 = new float[2];
float[] vv2 = new float[2];
float[] vv1_last = new float[2];
float[] vv2_last = new float[2];
float[][] vv = new float[2][2];
float[][] vv_last = new float[2][2];
int dir = 1;
int start = numv - 2;
int o_start = numc - 1;
int o_idx = 0;
byte o_flag = o_flags[o_idx];
int[] closed = { 0 };
boolean up;
boolean right;
int v_idx = start + dir * il * 2;
int cc_start = (dir > 0) ? (ctrLow - 1) : (ctrLow + (numc - 1));
// -- color level at corners
// ------------------------------
byte[][] crnr_color = new byte[4][color_length];
int[] crnrLevelIdx = new int[4];
boolean[] crnr_out = new boolean[] { true, true, true, true };
boolean all_out = true;
for (int tt = 0; tt < corners.length; tt++) {
int cc = 0;
int kk = 0;
for (kk = 0; kk < (values.length - 1); kk++) {
if ((corners[tt] >= values[kk])
&& (corners[tt] < values[kk + 1])) {
cc = kk;
all_out = false;
crnr_out[tt] = false;
}
}
for (int ii = 0; ii < color_length; ii++) {
crnr_color[tt][ii] = color_bin[ii][cc];
}
crnrLevelIdx[tt] = cc;
}
dir = 1;
start = numv - numc * 2;
o_start = 0;
v_idx = start + dir * il * 2;
up = false;
right = false;
float[] x_avg = new float[2];
float[] y_avg = new float[2];
if (numc > 1) { // -- first/next ctr line midpoints
int idx = v_idx;
x_avg[0] = (vx[idx] + vx[idx + 1]) / 2;
y_avg[0] = (vy[idx] + vy[idx + 1]) / 2;
idx = v_idx + 2;
x_avg[1] = (vx[idx] + vx[idx + 1]) / 2;
y_avg[1] = (vy[idx] + vy[idx + 1]) / 2;
if ((x_avg[1] - x_avg[0]) > 0)
up = true;
if ((y_avg[1] - y_avg[0]) > 0)
right = true;
} else if (numc == 1) { // - default values for logic below
x_avg[0] = 0f;
y_avg[0] = 0f;
x_avg[1] = 1f;
y_avg[1] = 1f;
} else if (numc == 0) // - empty grid box (no contour lines)
{
if (all_out)
return;
float[][] tri = new float[2][4];
float[][] normals = new float[3][4];
byte[] color = new byte[color_length];
for (int ii = 0; ii < color_length; ii++) {
color[ii] = crnr_color[0][ii];
}
normals[0][0] = grd_normals[nc][nr][0];
normals[1][0] = grd_normals[nc][nr][1];
normals[2][0] = grd_normals[nc][nr][2];
tri[0][0] = xx;
tri[1][0] = yy;
normals[0][1] = grd_normals[nc + 1][nr][0];
normals[1][1] = grd_normals[nc + 1][nr][1];
normals[2][1] = grd_normals[nc + 1][nr][2];
tri[0][1] = xx;
tri[1][1] = yy + yd;
normals[0][2] = grd_normals[nc][nr + 1][0];
normals[1][2] = grd_normals[nc][nr + 1][1];
normals[2][2] = grd_normals[nc][nr + 1][2];
tri[0][2] = xx + xd;
tri[1][2] = yy;
normals[0][3] = grd_normals[nc + 1][nr + 1][0];
normals[1][3] = grd_normals[nc + 1][nr + 1][1];
normals[2][3] = grd_normals[nc + 1][nr + 1][2];
tri[0][3] = xx + xd;
tri[1][3] = yy + yd;
byte first_tri_orient = CLOCKWISE;
byte last_tri_orient = CNTRCLOCKWISE;
byte first_strp_side = SIDE_LEFT;
byte last_strp_side = SIDE_RIGHT;
triStripBldr.addVerticies(crnrLevelIdx[0], tri, normals, color,
first_strp_side, first_tri_orient, last_strp_side,
last_tri_orient);
return;
} // -- end no contour lines
// If any case 6 (saddle point), handle all contour lines with special
// logic.
for (int iii = 0; iii < o_flags.length; iii++) {
if (o_flags[iii] > 32) {
fillCaseSix(xx, yy, xd, yd, v_idx, dir, o_flags, ctrLow, vx,
vy, nc, nr, crnr_color, crnrLevelIdx, crnr_out,
color_bin, color_length, grd_normals, closed,
triStripBldr);
return;
}
}
// -- start making triangles for color fill
// ---------------------------------------------
if (o_flag == 1 || o_flag == 4 || o_flag == 2 || o_flag == 7) {
boolean opp = false;
float dy = 0;
float dx = 0;
float dist_0 = 0;
float dist_1 = 0;
/**
* compare midpoints distances for first/next contour lines
* -------------------------------------------------
*/
if (o_flag == 1) {
dy = (y_avg[1] - (yy));
dx = (x_avg[1] - (xx));
dist_1 = dy * dy + dx * dx;
dy = (y_avg[0] - (yy));
dx = (x_avg[0] - (xx));
dist_0 = dy * dy + dx * dx;
}
if (o_flag == 2) {
dy = (y_avg[1] - (yy));
dx = (x_avg[1] - (xx + xd));
dist_1 = dy * dy + dx * dx;
dy = (y_avg[0] - (yy));
dx = (x_avg[0] - (xx + xd));
dist_0 = dy * dy + dx * dx;
}
if (o_flag == 4) {
dy = (y_avg[1] - (yy + yd));
dx = (x_avg[1] - (xx));
dist_1 = dy * dy + dx * dx;
dy = (y_avg[0] - (yy + yd));
dx = (x_avg[0] - (xx));
dist_0 = dy * dy + dx * dx;
}
if (o_flag == 7) {
dy = (y_avg[1] - (yy + yd));
dx = (x_avg[1] - (xx + xd));
dist_1 = dy * dy + dx * dx;
dy = (y_avg[0] - (yy + yd));
dx = (x_avg[0] - (xx + xd));
dist_0 = dy * dy + dx * dx;
}
if (dist_1 < dist_0)
opp = true;
if (opp) {
fillToOppCorner(xx, yy, xd, yd, v_idx, o_flag, dir, vx, vy, nc,
nr, crnr_color, crnrLevelIdx, crnr_out, grd_normals,
closed, triStripBldr);
} else {
fillToNearCorner(xx, yy, xd, yd, v_idx, o_flag, dir, vx, vy,
nc, nr, crnr_color, crnrLevelIdx, crnr_out,
grd_normals, closed, triStripBldr);
}
} else if (o_flags[o_idx] == 3) {
int flag = 1;
if (right)
flag = -1;
fillToSide(xx, yy, xd, yd, v_idx, o_flag, flag, dir, vx, vy, nc,
nr, crnr_color, crnrLevelIdx, crnr_out, grd_normals,
closed, triStripBldr);
} else if (o_flags[o_idx] == 5) {
int flag = 1;
if (!up)
flag = -1;
fillToSide(xx, yy, xd, yd, v_idx, o_flag, flag, dir, vx, vy, nc,
nr, crnr_color, crnrLevelIdx, crnr_out, grd_normals,
closed, triStripBldr);
}
byte last_o = o_flags[o_idx];
// - move to next contour line
// --------------------------------
il++;
for (il = 1; il < numc; il++) { // - iterate over contour line box
// intersection segments
v_idx = start + dir * il * 2;
o_idx = o_start + dir * il;
int v_idx_last = v_idx - 2 * dir;
int cc = cc_start + dir * il;
if (o_flags[o_idx] != last_o) // - contour line case change
{
// - box side of line segment verticies, 0->v_idx,
// 1->v_idx->v_idx+1
byte[] side_s = new byte[2];
// - box side of last line segment verticies, 0->v_idx_last,
// 1->v_idx->v_idx_last+1
byte[] last_side_s = new byte[2];
boolean flip;
getBoxSide(vx, vy, xx, xd, yy, yd, v_idx, dir, o_flags[o_idx],
side_s);
getBoxSide(vx, vy, xx, xd, yy, yd, v_idx_last, dir, last_o,
last_side_s);
// -1: no line segment points lie on the same box side
// 0:
// 1:
int same_side_idx = -1;
if (side_s[0] == last_side_s[0]) {
flip = false;
same_side_idx = 0;
} else if (side_s[0] == last_side_s[1]) {
flip = true;
same_side_idx = 1;
} else if (side_s[1] == last_side_s[0]) {
flip = true;
same_side_idx = 0;
} else if (side_s[1] == last_side_s[1]) {
flip = false;
same_side_idx = 1;
} else {
if (((side_s[0] + last_side_s[0]) & 1) == 1) { // flip so
// 0idx and
// 1idx on
// opposite
// sides
flip = false;
} else {
flip = true;
}
}
// - flip only (v_idx, v_idx+1) line segment, not 'last', ie.
// (v_idx_last, v_idx_last+1)
if (!flip) {
vv1[0] = vx[v_idx];
vv1[1] = vy[v_idx];
vv2[0] = vx[v_idx + dir];
vv2[1] = vy[v_idx + dir];
vv[0][0] = vx[v_idx];
vv[1][0] = vy[v_idx];
vv[0][1] = vx[v_idx + dir];
vv[1][1] = vy[v_idx + dir];
} else { // do the flip
vv1[0] = vx[v_idx + dir];
vv1[1] = vy[v_idx + dir];
vv2[0] = vx[v_idx];
vv2[1] = vy[v_idx];
vv[0][0] = vx[v_idx + dir];
vv[1][0] = vy[v_idx + dir];
vv[0][1] = vx[v_idx];
vv[1][1] = vy[v_idx];
// - reflect that the flipped occurred.
byte tmp = side_s[0];
side_s[0] = side_s[1];
side_s[1] = tmp;
}
vv1_last[0] = vx[v_idx_last];
vv1_last[1] = vy[v_idx_last];
vv2_last[0] = vx[v_idx_last + dir];
vv2_last[1] = vy[v_idx_last + dir];
vv_last[0][0] = vx[v_idx_last];
vv_last[1][0] = vy[v_idx_last];
vv_last[0][1] = vx[v_idx_last + dir];
vv_last[1][1] = vy[v_idx_last + dir];
fillCaseChange(xx, yy, xd, yd, nc, nr, vv1, vv2, vv1_last,
vv2_last, color_bin, cc, color_length, grd_normals,
closed, same_side_idx, side_s, last_side_s,
triStripBldr);
} else {
vv1[0] = vx[v_idx];
vv1[1] = vy[v_idx];
vv2[0] = vx[v_idx + dir];
vv2[1] = vy[v_idx + dir];
vv1_last[0] = vx[v_idx_last];
vv1_last[1] = vy[v_idx_last];
vv2_last[0] = vx[v_idx_last + dir];
vv2_last[1] = vy[v_idx_last + dir];
fillToLast(xx, yy, xd, yd, nc, nr, vv1, vv2, vv1_last,
vv2_last, o_flags[o_idx], color_bin, cc, color_length,
grd_normals, -1, triStripBldr);
}
last_o = o_flags[o_idx];
} // ---- contour lines loop
/*- last or first/last contour line
------------------------------------*/
int flag_set = 0;
if ((last_o == 1) || (last_o == 2) || (last_o == 4) || (last_o == 7)) {
if (last_o == 1)
flag_set = (closed[0] & 1);
if (last_o == 2)
flag_set = (closed[0] & 2);
if (last_o == 4)
flag_set = (closed[0] & 4);
if (last_o == 7)
flag_set = (closed[0] & 8);
if (flag_set > 0) {
fillToOppCorner(xx, yy, xd, yd, v_idx, last_o, dir, vx, vy, nc,
nr, crnr_color, crnrLevelIdx, crnr_out, grd_normals,
closed, triStripBldr);
} else {
fillToNearCorner(xx, yy, xd, yd, v_idx, last_o, dir, vx, vy,
nc, nr, crnr_color, crnrLevelIdx, crnr_out,
grd_normals, closed, triStripBldr);
}
} else if (last_o == 3) {
int flag = -1;
if (closed[0] == 3)
flag = 1;
fillToSide(xx, yy, xd, yd, v_idx, last_o, flag, dir, vx, vy, nc,
nr, crnr_color, crnrLevelIdx, crnr_out, grd_normals,
closed, triStripBldr);
} else if (last_o == 5) {
int flag = 1;
if (closed[0] == 5)
flag = -1;
fillToSide(xx, yy, xd, yd, v_idx, last_o, flag, dir, vx, vy, nc,
nr, crnr_color, crnrLevelIdx, crnr_out, grd_normals,
closed, triStripBldr);
}
} // --- end fillGridBox
/**
*
* @param vx
* @param vy
* @param xx
* @param xd
* @param yy
* @param yd
* @param v_idx
* @param dir
* @param o_flag
* @param side
*/
private static void getBoxSide(float[] vx, float[] vy, float xx, float xd,
float yy, float yd, int v_idx, int dir, byte o_flag, byte[] side) {
/*
* if (vy[v_idx] == yy) side[0] = 0; // a-b if (vy[v_idx] == (yy + yd))
* side[0] = 2; // c-d if (vx[v_idx] == xx) side[0] = 3; // a-c if
* (vx[v_idx] == (xx + xd)) side[0] = 1; // b-d
*/
for (int kk = 0; kk < 2; kk++) {
int ii = v_idx + kk * dir;
switch (o_flag) {
case 1:
side[kk] = 3;
if (vy[ii] == yy)
side[kk] = 0;
break;
case 2:
side[kk] = 1;
if (vy[ii] == yy)
side[kk] = 0;
break;
case 4:
side[kk] = 3;
if (vy[ii] == (yy + yd))
side[kk] = 2;
break;
case 7:
side[kk] = 1;
if (vy[ii] == (yy + yd))
side[kk] = 2;
break;
case 3:
side[kk] = 1;
if (vx[ii] == xx)
side[kk] = 3;
break;
case 5:
side[kk] = 0;
if (vy[ii] == (yy + yd))
side[kk] = 2;
break;
}
}
// - check for degenerate corner case, ie both intersection points on a
// corner
switch (o_flag) {
case 1:
if (side[0] == side[1]) {
side[0] = 0;
side[1] = 3;
}
break;
case 2:
if (side[0] == side[1]) {
side[0] = 0;
side[1] = 1;
}
break;
case 4:
if (side[0] == side[1]) {
side[0] = 3;
side[1] = 2;
}
break;
case 7:
if (side[0] == side[1]) {
side[0] = 1;
side[1] = 2;
}
break;
}
}
/**
*
* @param vx
* @param vy
* @param xx
* @param yy
* @param nc
* @param nr
* @param xd
* @param yd
* @param grd_normals
* @param n_idx
* @param tri_normals
*/
private static void interpNormals(float[] vx, float[] vy, float xx,
float yy, int nc, int nr, float xd, float yd,
float[][][] grd_normals, float[][] tri_normals) {
int n_verts = vx.length;
float[][] tmp = new float[3][1];
for (int k = 0; k < n_verts; k++) {
interpNormals(vx[k], vy[k], xx, yy, nc, nr, xd, yd, grd_normals,
tmp);
tri_normals[0][k] = tmp[0][0];
tri_normals[1][k] = tmp[1][0];
tri_normals[2][k] = tmp[2][0];
}
}
private static void interpNormals(float vx, float vy, float xx, float yy,
int nc, int nr, float xd, float yd, float[][][] grd_normals,
float[][] tri_normals) {
int[] n_idx = new int[] { 0 };
float[] temp = new float[3];
interpNormals(vx, vy, xx, yy, nc, nr, xd, yd, grd_normals, n_idx, temp);
tri_normals[0][0] = temp[0];
tri_normals[1][0] = temp[1];
tri_normals[2][0] = temp[2];
}
private static void interpNormals(float vx, float vy, float xx, float yy,
int nc, int nr, float xd, float yd, float[][][] grd_normals,
int[] n_idx, float[] tri_normals) {
int side = -1;
float[] nn = new float[3];
if (vy == yy)
side = 0; // a-b
if (vy == (yy + yd))
side = 2; // c-d
if (vx == xx)
side = 3; // a-c
if (vx == (xx + xd))
side = 1; // b-d
float dx = vx - xx;
float dy = vy - yy;
switch (side) {
case 0:
nn[0] = ((grd_normals[nc][nr + 1][0] - grd_normals[nc][nr][0]) / xd)
* dx + grd_normals[nc][nr][0];
nn[1] = ((grd_normals[nc][nr + 1][1] - grd_normals[nc][nr][1]) / xd)
* dx + grd_normals[nc][nr][1];
nn[2] = ((grd_normals[nc][nr + 1][2] - grd_normals[nc][nr][2]) / xd)
* dx + grd_normals[nc][nr][2];
break;
case 3:
nn[0] = ((grd_normals[nc + 1][nr][0] - grd_normals[nc][nr][0]) / yd)
* dy + grd_normals[nc][nr][0];
nn[1] = ((grd_normals[nc + 1][nr][1] - grd_normals[nc][nr][1]) / yd)
* dy + grd_normals[nc][nr][1];
nn[2] = ((grd_normals[nc + 1][nr][2] - grd_normals[nc][nr][2]) / yd)
* dy + grd_normals[nc][nr][2];
break;
case 1:
nn[0] = ((grd_normals[nc + 1][nr + 1][0] - grd_normals[nc][nr + 1][0]) / yd)
* dy + grd_normals[nc][nr + 1][0];
nn[1] = ((grd_normals[nc + 1][nr + 1][1] - grd_normals[nc][nr + 1][1]) / yd)
* dy + grd_normals[nc][nr + 1][1];
nn[2] = ((grd_normals[nc + 1][nr + 1][2] - grd_normals[nc][nr + 1][2]) / yd)
* dy + grd_normals[nc][nr + 1][2];
break;
case 2:
nn[0] = ((grd_normals[nc + 1][nr + 1][0] - grd_normals[nc + 1][nr][0]) / xd)
* dx + grd_normals[nc + 1][nr][0];
nn[1] = ((grd_normals[nc + 1][nr + 1][1] - grd_normals[nc + 1][nr][1]) / xd)
* dx + grd_normals[nc + 1][nr][1];
nn[2] = ((grd_normals[nc + 1][nr + 1][2] - grd_normals[nc + 1][nr][2]) / xd)
* dx + grd_normals[nc + 1][nr][2];
break;
default:
System.out.println("interpNormals, bad side: " + side);
}
// - re-normalize
float mag = (float) Math.sqrt(nn[0] * nn[0] + nn[1] * nn[1] + nn[2]
* nn[2]);
nn[0] /= mag;
nn[1] /= mag;
nn[2] /= mag;
tri_normals[n_idx[0]++] = nn[0];
tri_normals[n_idx[0]++] = nn[1];
tri_normals[n_idx[0]++] = nn[2];
}
/**
*
* @param xx
* @param yy
* @param xd
* @param yd
* @param nc
* @param nr
* @param vv1
* @param vv2
* @param vv1_last
* @param vv2_last
* @param kase
* @param color_bin
* @param cc
* @param color_length
* @param grd_normals
* @param same_side_idx
* @param triStripBldr
*/
private static void fillToLast(float xx, float yy, float xd, float yd,
int nc, int nr, float[] vv1, float[] vv2, float[] vv1_last,
float[] vv2_last, byte kase, byte[][] color_bin, int cc,
int color_length, float[][][] grd_normals, int same_side_idx,
TriangleStripBuilder triStripBldr) {
float[][] tri = new float[2][4];
float[][] normals = new float[3][4];
byte[] side_s = new byte[2];
byte[] last_side_s = new byte[2];
byte[] strp_sides = new byte[4];
int startIdx = 0;
float[] vx = new float[2];
float[] vy = new float[2];
vx[0] = vv1[0];
vx[1] = vv2[0];
vy[0] = vv1[1];
vy[1] = vv2[1];
getBoxSide(vx, vy, xx, xd, yy, yd, 0, 1, kase, side_s);
vx[0] = vv1_last[0];
vx[1] = vv2_last[0];
vy[0] = vv1_last[1];
vy[1] = vv2_last[1];
getBoxSide(vx, vy, xx, xd, yy, yd, 0, 1, kase, last_side_s);
fillToLast(xx, yy, xd, yd, nc, nr, vv1, vv2, vv1_last, vv2_last,
color_bin, cc, color_length, grd_normals, same_side_idx,
side_s, last_side_s, strp_sides, tri, normals, startIdx,
triStripBldr);
}
private static void fillToLast(float xx, float yy, float xd, float yd,
int nc, int nr, float[] vv1, float[] vv2, float[] vv1_last,
float[] vv2_last, byte[][] color_bin, int cc, int color_length,
float[][][] grd_normals, int same_side_idx, byte[] side_s,
byte[] last_side_s, byte[] strp_sides, float[][] tri,
float[][] normals, int startIdx, TriangleStripBuilder triStripBldr) {
float x0, y0, x1, y1, x2, y2, x3, y3;
float[][] tmp = new float[3][1];
byte[] color = new byte[color_length];
for (int ii = 0; ii < color_length; ii++) {
color[ii] = color_bin[ii][cc];
}
if (same_side_idx <= 0) {
x0 = vv1[0];
y0 = vv1[1];
x1 = vv1_last[0];
y1 = vv1_last[1];
x2 = vv2[0];
y2 = vv2[1];
x3 = vv2_last[0];
y3 = vv2_last[1];
strp_sides[0] = side_s[0];
strp_sides[1] = last_side_s[0];
strp_sides[2] = side_s[1];
strp_sides[3] = last_side_s[1];
} else {
x0 = vv2[0];
y0 = vv2[1];
x1 = vv2_last[0];
y1 = vv2_last[1];
x2 = vv1[0];
y2 = vv1[1];
x3 = vv1_last[0];
y3 = vv1_last[1];
strp_sides[0] = side_s[1];
strp_sides[1] = last_side_s[1];
strp_sides[2] = side_s[0];
strp_sides[3] = last_side_s[0];
}
int idx = startIdx + 0;
tri[0][idx] = x0;
tri[1][idx] = y0;
interpNormals(tri[0][idx], tri[1][idx], xx, yy, nc, nr, xd, yd,
grd_normals, tmp);
normals[0][idx] = tmp[0][0];
normals[1][idx] = tmp[1][0];
normals[2][idx] = tmp[2][0];
idx = startIdx + 1;
tri[0][idx] = x1;
tri[1][idx] = y1;
interpNormals(tri[0][idx], tri[1][idx], xx, yy, nc, nr, xd, yd,
grd_normals, tmp);
normals[0][idx] = tmp[0][0];
normals[1][idx] = tmp[1][0];
normals[2][idx] = tmp[2][0];
idx = startIdx + 2;
tri[0][idx] = x2;
tri[1][idx] = y2;
interpNormals(tri[0][idx], tri[1][idx], xx, yy, nc, nr, xd, yd,
grd_normals, tmp);
normals[0][idx] = tmp[0][0];
normals[1][idx] = tmp[1][0];
normals[2][idx] = tmp[2][0];
idx = startIdx + 3;
tri[0][idx] = x3;
tri[1][idx] = y3;
interpNormals(tri[0][idx], tri[1][idx], xx, yy, nc, nr, xd, yd,
grd_normals, tmp);
normals[0][idx] = tmp[0][0];
normals[1][idx] = tmp[1][0];
normals[2][idx] = tmp[2][0];
if (triStripBldr != null) {
byte first_tri_orient = 0;
byte last_tri_orient = 0;
byte kase = strp_sides[0];
byte first_strp_side = strp_sides[0];
byte last_strp_side = strp_sides[3];
switch (kase) {
case 1:
if ((tri[0][1] - tri[0][0]) >= 0) {
first_tri_orient = 1;
last_tri_orient = -1;
} else {
first_tri_orient = -1;
last_tri_orient = 1;
}
break;
case 2:
if ((tri[0][1] - tri[0][0]) >= 0) {
first_tri_orient = 1;
last_tri_orient = -1;
} else {
first_tri_orient = -1;
last_tri_orient = 1;
}
break;
case 4:
if ((tri[1][1] - tri[1][0]) >= 0) {
first_tri_orient = -1;
last_tri_orient = 1;
} else {
first_tri_orient = 1;
last_tri_orient = -1;
}
break;
case 7:
if ((tri[1][1] - tri[1][0]) >= 0) {
first_tri_orient = 1;
last_tri_orient = -1;
} else {
first_tri_orient = -1;
last_tri_orient = 1;
}
break;
case 3:
if ((tri[1][1] - tri[1][0]) >= 0) {
first_tri_orient = -1;
last_tri_orient = 1;
} else {
first_tri_orient = 1;
last_tri_orient = -1;
}
break;
case 5:
if ((tri[0][1] - tri[0][0]) >= 0) {
first_tri_orient = 1;
last_tri_orient = -1;
} else {
first_tri_orient = -1;
last_tri_orient = 1;
}
break;
}
triStripBldr.addVerticies(cc, tri, normals, color, first_strp_side,
first_tri_orient, last_strp_side, last_tri_orient);
}
}
private static void fillCaseChange(float xx, float yy, float xd, float yd,
int nc, int nr, float[] vv1, float[] vv2, float[] vv1_last,
float[] vv2_last, byte[][] color_bin, int cc, int color_length,
float[][][] grd_normals, int[] closed, int same_side_idx,
byte[] side_s, byte[] last_side_s, TriangleStripBuilder triStripBldr) {
float[][] tri = null;
float[][] normals = null;
byte first_tri_orient = 0;
byte last_tri_orient = 0;
byte first_strp_side = SIDE_NONE;
byte last_strp_side = SIDE_NONE;
byte[] strp_sides = new byte[4];
byte[] color = new byte[color_length];
for (int k = 0; k < color_length; k++)
color[k] = color_bin[k][cc];
/*
* no line segments points are on the same box side. Close off (2)
* opposite corners
*/
if (same_side_idx == -1) {
tri = new float[2][6];
normals = new float[3][6];
// - use box side of first point in both contour segments.
byte side = side_s[0];
byte last_s = last_side_s[0];
byte[] cornersToAdd = new byte[2];
fillToLast(xx, yy, xd, yd, nc, nr, vv1, vv2, vv1_last, vv2_last,
color_bin, cc, color_length, grd_normals, same_side_idx,
side_s, last_side_s, strp_sides, tri, normals, 1, null);
if ((side == 0 && last_s == 1) || (side == 3 && last_s == 2)
|| (side == 2 && last_s == 3) || (side == 1 && last_s == 0)) {
if (strp_sides[0] == 0 && strp_sides[1] == 1) {
cornersToAdd[0] = 1;
cornersToAdd[1] = 2;
first_tri_orient = -1;
last_tri_orient = 1;
}
if (strp_sides[0] == 1 && strp_sides[1] == 0) {
cornersToAdd[0] = 1;
cornersToAdd[1] = 2;
first_tri_orient = 1;
last_tri_orient = -1;
}
if (strp_sides[0] == 3 && strp_sides[1] == 2) {
cornersToAdd[0] = 2;
cornersToAdd[1] = 1;
first_tri_orient = 1;
last_tri_orient = -1;
}
if (strp_sides[0] == 2 && strp_sides[1] == 3) {
cornersToAdd[0] = 2;
cornersToAdd[1] = 1;
first_tri_orient = -1;
last_tri_orient = 1;
}
}
if ((side == 0 && last_s == 3) || (side == 1 && last_s == 2)
|| (side == 3 && last_s == 0) || (side == 2 && last_s == 1)) {
if (strp_sides[0] == 0 && strp_sides[1] == 3) {
cornersToAdd[0] = 0;
cornersToAdd[1] = 3;
first_tri_orient = 1;
last_tri_orient = -1;
}
if (strp_sides[0] == 3 && strp_sides[1] == 0) {
cornersToAdd[0] = 0;
cornersToAdd[1] = 3;
first_tri_orient = -1;
last_tri_orient = 1;
}
if (strp_sides[0] == 1 && strp_sides[1] == 2) {
cornersToAdd[0] = 3;
cornersToAdd[1] = 0;
first_tri_orient = -1;
last_tri_orient = 1;
}
if (strp_sides[0] == 2 && strp_sides[1] == 1) {
cornersToAdd[0] = 3;
cornersToAdd[1] = 0;
first_tri_orient = 1;
last_tri_orient = -1;
}
}
first_strp_side = strp_sides[0];
last_strp_side = strp_sides[3];
addCorner(xx, yy, xd, yd, nc, nr, cornersToAdd[0], grd_normals,
closed, 0, tri, normals);
addCorner(xx, yy, xd, yd, nc, nr, cornersToAdd[1], grd_normals,
closed, 5, tri, normals);
triStripBldr.addVerticies(cc, tri, normals, color, first_strp_side,
first_tri_orient, last_strp_side, last_tri_orient);
} else { // - 2 line segment end points have the same box side
byte side, last_s;
int indx = (same_side_idx == 0) ? 1 : 0;
side = side_s[indx];
last_s = last_side_s[indx];
byte kase = 0;
if ((side == 0 && last_s == 3) || (side == 3 && last_s == 0))
kase = 1;
if ((side == 0 && last_s == 1) || (side == 1 && last_s == 0))
kase = 2;
if ((side == 2 && last_s == 3) || (side == 3 && last_s == 2))
kase = 4;
if ((side == 2 && last_s == 1) || (side == 1 && last_s == 2))
kase = 7;
if ((side == 1 && last_s == 3) || (side == 3 && last_s == 1))
kase = 3;
if ((side == 2 && last_s == 0) || (side == 0 && last_s == 2))
kase = 5;
if (kase == 1 || kase == 2 || kase == 4 || kase == 7) { // close off
// (1)
// corner
byte cornerId = 127;
tri = new float[2][5];
normals = new float[3][5];
fillToLast(xx, yy, xd, yd, nc, nr, vv1, vv2, vv1_last,
vv2_last, color_bin, cc, color_length, grd_normals,
same_side_idx, side_s, last_side_s, strp_sides, tri,
normals, 0, null);
if (kase == 1) {
cornerId = 0;
last_strp_side = strp_sides[3];
first_strp_side = strp_sides[0];
if (last_strp_side == 3) {
last_tri_orient = 1;
first_tri_orient = 1;
} else if (last_strp_side == 0) {
last_tri_orient = -1;
first_tri_orient = -1;
}
}
if (kase == 2) {
cornerId = 1;
last_strp_side = strp_sides[3];
first_strp_side = strp_sides[0];
if (last_strp_side == 1) {
last_tri_orient = -1;
first_tri_orient = -1;
} else if (last_strp_side == 0) {
last_tri_orient = 1;
first_tri_orient = 1;
}
}
if (kase == 4) {
cornerId = 2;
last_strp_side = strp_sides[3];
first_strp_side = strp_sides[0];
if (last_strp_side == 2) {
last_tri_orient = 1;
first_tri_orient = 1;
} else if (last_strp_side == 3) {
last_tri_orient = -1;
first_tri_orient = -1;
}
}
if (kase == 7) {
cornerId = 3;
last_strp_side = strp_sides[3];
first_strp_side = strp_sides[0];
if (last_strp_side == 2) {
last_tri_orient = -1;
first_tri_orient = -1;
} else if (last_strp_side == 1) {
last_tri_orient = 1;
first_tri_orient = 1;
}
}
addCorner(xx, yy, xd, yd, nc, nr, cornerId, grd_normals,
closed, 4, tri, normals);
} else if (kase == 5) { // close off (2) adjacent corners
byte[] oppCorners = new byte[] { 127, 127 };
byte same_side = side_s[same_side_idx];
tri = new float[2][6];
normals = new float[3][6];
fillToLast(xx, yy, xd, yd, nc, nr, vv1, vv2, vv1_last,
vv2_last, color_bin, cc, color_length, grd_normals,
same_side_idx, side_s, last_side_s, strp_sides, tri,
normals, 0, null);
if (same_side == 1) {
if (strp_sides[3] == 2) {
oppCorners = new byte[] { 0, 2 };
first_tri_orient = 1;
last_tri_orient = -1;
first_strp_side = 1;
last_strp_side = 3;
} else if (strp_sides[3] == 0) {
oppCorners = new byte[] { 2, 0 };
first_tri_orient = -1;
last_tri_orient = 1;
first_strp_side = 1;
last_strp_side = 3;
}
}
if (same_side == 3) {
if (strp_sides[3] == 2) {
oppCorners = new byte[] { 1, 3 };
first_tri_orient = -1;
last_tri_orient = 1;
first_strp_side = 3;
last_strp_side = 1;
} else if (strp_sides[3] == 0) {
oppCorners = new byte[] { 3, 1 };
first_tri_orient = 1;
last_tri_orient = -1;
first_strp_side = 3;
last_strp_side = 1;
}
}
addCorner(xx, yy, xd, yd, nc, nr, oppCorners[0], grd_normals,
closed, 4, tri, normals);
addCorner(xx, yy, xd, yd, nc, nr, oppCorners[1], grd_normals,
closed, 5, tri, normals);
} else if (kase == 3) { // - close off (2) adjacent corners
byte[] oppCorners = new byte[] { 127, 127 };
byte same_side = side_s[same_side_idx];
tri = new float[2][6];
normals = new float[3][6];
fillToLast(xx, yy, xd, yd, nc, nr, vv1, vv2, vv1_last,
vv2_last, color_bin, cc, color_length, grd_normals,
same_side_idx, side_s, last_side_s, strp_sides, tri,
normals, 0, null);
if (same_side == 0) {
if (strp_sides[3] == 3) {
oppCorners = new byte[] { 3, 2 };
first_tri_orient = -1;
last_tri_orient = 1;
first_strp_side = 0;
last_strp_side = 2;
} else if (strp_sides[3] == 1) {
oppCorners = new byte[] { 2, 3 };
first_tri_orient = 1;
last_tri_orient = -1;
first_strp_side = 0;
last_strp_side = 2;
}
}
if (same_side == 2) {
if (strp_sides[3] == 3) {
oppCorners = new byte[] { 1, 0 };
first_tri_orient = 1;
last_tri_orient = -1;
first_strp_side = 2;
last_strp_side = 0;
} else if (strp_sides[3] == 1) {
oppCorners = new byte[] { 0, 1 };
first_tri_orient = -1;
last_tri_orient = 1;
first_strp_side = 2;
last_strp_side = 0;
}
}
addCorner(xx, yy, xd, yd, nc, nr, oppCorners[0], grd_normals,
closed, 4, tri, normals);
addCorner(xx, yy, xd, yd, nc, nr, oppCorners[1], grd_normals,
closed, 5, tri, normals);
}
triStripBldr.addVerticies(cc, tri, normals, color, first_strp_side,
first_tri_orient, last_strp_side, last_tri_orient);
}
}
/**
*
* @param xx
* @param yy
* @param xd
* @param yd
* @param v_idx
* @param dir
* @param o_flags
* @param ctrLow
* @param vx
* @param vy
* @param nc
* @param nr
* @param crnr_color
* @param crnrLevelIdx
* @param crnr_out
* @param color_bin
* @param color_length
* @param grd_normals
* @param closed
* @param triStripBldr
*/
private static void fillCaseSix(float xx, float yy, float xd, float yd,
int v_idx, int dir, byte[] o_flags, short ctrLow, float[] vx,
float[] vy, int nc, int nr, byte[][] crnr_color,
int[] crnrLevelIdx, boolean[] crnr_out, byte[][] color_bin,
int color_length, float[][][] grd_normals, int[] closed,
TriangleStripBuilder triStripBldr) {
float[][] tri = null;
int n1 = 0; // - number of case1 line segments
int n2 = 0; // - case2
int n4 = 0; // - case4
int n7 = 0; // - case7
for (int kk = 0; kk < o_flags.length; kk++) {
if ((o_flags[kk] - 32) == 1 || o_flags[kk] == 1)
n1++;
if ((o_flags[kk] - 32) == 2 || o_flags[kk] == 2)
n2++;
if ((o_flags[kk] - 32) == 4 || o_flags[kk] == 4)
n4++;
if ((o_flags[kk] - 32) == 7 || o_flags[kk] == 7)
n7++;
}
// - all case coords in separate arrays
float[][] vv1 = new float[2][n1 * 2]; // - all case1 coords in one array
float[][] vv2 = new float[2][n2 * 2]; // 2
float[][] vv4 = new float[2][n4 * 2]; // 4
float[][] vv7 = new float[2][n7 * 2]; // 7
int[] clr_idx1 = new int[n1];
int[] clr_idx2 = new int[n2];
int[] clr_idx4 = new int[n4];
int[] clr_idx7 = new int[n7];
float[] vvv1 = new float[2];
float[] vvv2 = new float[2];
float[] vvv1_last = new float[2];
float[] vvv2_last = new float[2];
n1 = 0;
n2 = 0;
n4 = 0;
n7 = 0;
int ii = v_idx;
int cc = ctrLow - 1;
int cnt = 0;
int[] cases = { 1, 2, 7, 4 }; // - corner cases, counter-clockwise
// around box
for (int kk = 0; kk < o_flags.length; kk++) {
if (o_flags[kk] > 32)
cnt++;
if ((o_flags[kk] - 32) == 1 || o_flags[kk] == 1) {
clr_idx1[n1] = cc;
vv1[0][2 * n1] = vx[ii];
vv1[1][2 * n1] = vy[ii];
vv1[0][2 * n1 + 1] = vx[ii + 1];
vv1[1][2 * n1 + 1] = vy[ii + 1];
n1++;
} else if ((o_flags[kk] - 32) == 2 || o_flags[kk] == 2) {
clr_idx2[n2] = cc;
vv2[0][2 * n2] = vx[ii];
vv2[1][2 * n2] = vy[ii];
vv2[0][2 * n2 + 1] = vx[ii + 1];
vv2[1][2 * n2 + 1] = vy[ii + 1];
n2++;
} else if ((o_flags[kk] - 32) == 4 || o_flags[kk] == 4) {
clr_idx4[n4] = cc;
vv4[0][2 * n4] = vx[ii];
vv4[1][2 * n4] = vy[ii];
vv4[0][2 * n4 + 1] = vx[ii + 1];
vv4[1][2 * n4 + 1] = vy[ii + 1];
n4++;
} else if ((o_flags[kk] - 32) == 7 || o_flags[kk] == 7) {
clr_idx7[n7] = cc;
vv7[0][2 * n7] = vx[ii];
vv7[1][2 * n7] = vy[ii];
vv7[0][2 * n7 + 1] = vx[ii + 1];
vv7[1][2 * n7 + 1] = vy[ii + 1];
n7++;
}
if (o_flags[kk] < 32) {
cc += 1;
} else if (cnt == 2) {
cnt = 0;
cc++;
}
ii += 2;
}
int[] clr_idx = null;
float[] vvx = null;
float[] vvy = null;
float[] x_avg = new float[2];
float[] y_avg = new float[2];
float dist_0 = 0;
float dist_1 = 0;
float xxx = 0;
float yyy = 0;
float dx = 0;
float dy = 0;
int nn = 0;
int pt = 0;
int n_pt = 0;
int s_idx = 0;
int ns_idx = 0;
byte[] tmp = null;
byte[] cntr_color = null;
int cntr_clr = Integer.MIN_VALUE;
float[][] edge_points = new float[2][8];
boolean[] edge_point_a_corner = { false, false, false, false, false,
false, false, false };
boolean[] edge_point_out = { false, false, false, false, false, false,
false, false };
boolean this_crnr_out = false;
int n_crnr_out = 0;
int[] which_corner = new int[2]; // - use case values
int num_corners = 0;
/*
* Letters are the grid corners consistent with previous definition.
* Numbers are indexes into the edge_points array. Note, if there is no
* corner line segement, the adjacent indexes both refer to the corner:
* 4,3 -> D, 6,5 -> C, 0,7 -> A, 1,2 -> B, otherwise they are the
* contour line segment intersection points.
*
* C------(5)-------(4)------D | | | | | | (6) (3) | | | | | | (7) (2) |
* | | | | | A------(0)-------(1)------B
*/
/*
* Iterate through cases, they're all corners, and create the fill
* geometry. When finished the final edge points are used below to fill
* the remainder of the grid box.
*/
for (int kk = 0; kk < cases.length; kk++) {
switch (cases[kk]) {
case 1:
nn = n1;
clr_idx = clr_idx1;
vvx = vv1[0];
vvy = vv1[1];
xxx = xx;
yyy = yy;
pt = 0;
n_pt = 7;
s_idx = 0;
ns_idx = 1;
tmp = crnr_color[0];
this_crnr_out = crnr_out[0];
break;
case 2:
nn = n2;
clr_idx = clr_idx2;
vvx = vv2[0];
vvy = vv2[1];
xxx = xx + xd;
yyy = yy;
pt = 1;
n_pt = 2;
s_idx = 0;
ns_idx = 1;
tmp = crnr_color[1];
this_crnr_out = crnr_out[1];
break;
case 4:
nn = n4;
clr_idx = clr_idx4;
vvx = vv4[0];
vvy = vv4[1];
xxx = xx;
yyy = yy + yd;
pt = 5;
n_pt = 6;
s_idx = 1;
ns_idx = 0;
tmp = crnr_color[2];
this_crnr_out = crnr_out[2];
break;
case 7:
nn = n7;
clr_idx = clr_idx7;
vvx = vv7[0];
vvy = vv7[1];
xxx = xx + xd;
yyy = yy + yd;
pt = 3;
n_pt = 4;
s_idx = 0;
ns_idx = 1;
tmp = crnr_color[3];
this_crnr_out = crnr_out[3];
break;
}
if (nn == 0) {
edge_points[0][pt] = xxx;
edge_points[1][pt] = yyy;
edge_points[0][n_pt] = xxx;
edge_points[1][n_pt] = yyy;
cntr_color = tmp;
edge_point_a_corner[pt] = true;
edge_point_a_corner[n_pt] = true;
edge_point_out[pt] = this_crnr_out;
edge_point_out[n_pt] = this_crnr_out;
which_corner[num_corners] = cases[kk];
num_corners++;
if (this_crnr_out)
n_crnr_out++;
} else if (nn == 1) {
fillToNearCorner(xx, yy, xd, yd, 0, (byte) cases[kk], dir, vvx,
vvy, nc, nr, crnr_color, crnrLevelIdx, crnr_out,
grd_normals, closed, triStripBldr);
edge_points[0][pt] = vvx[s_idx];
edge_points[1][pt] = vvy[s_idx];
edge_points[0][n_pt] = vvx[ns_idx];
edge_points[1][n_pt] = vvy[ns_idx];
if (clr_idx[0] > cntr_clr)
cntr_clr = clr_idx[0];
} else {
int il = 0;
int idx = 0;
x_avg[0] = (vvx[idx] + vvx[idx + 1]) / 2;
y_avg[0] = (vvy[idx] + vvy[idx + 1]) / 2;
idx = idx + 2;
x_avg[1] = (vvx[idx] + vvx[idx + 1]) / 2;
y_avg[1] = (vvy[idx] + vvy[idx + 1]) / 2;
dy = (y_avg[1] - (yyy));
dx = (x_avg[1] - (xxx));
dist_1 = dy * dy + dx * dx;
dy = (y_avg[0] - (yyy));
dx = (x_avg[0] - (xxx));
dist_0 = dy * dy + dx * dx;
boolean cornerFirst = false;
if (dist_1 > dist_0)
cornerFirst = true;
if (cornerFirst) {
fillToNearCorner(xx, yy, xd, yd, 0, (byte) cases[kk], dir,
vvx, vvy, nc, nr, crnr_color, crnrLevelIdx,
crnr_out, grd_normals, closed, triStripBldr);
} else {
edge_points[0][pt] = vvx[s_idx];
edge_points[1][pt] = vvy[s_idx];
edge_points[0][n_pt] = vvx[ns_idx];
edge_points[1][n_pt] = vvy[ns_idx];
if (clr_idx[0] > cntr_clr)
cntr_clr = clr_idx[0];
}
for (il = 1; il < nn; il++) {
idx = dir * il * 2;
int idx_last = idx - 2 * dir;
vvv1[0] = vvx[idx];
vvv1[1] = vvy[idx];
vvv2[0] = vvx[idx + dir];
vvv2[1] = vvy[idx + dir];
vvv1_last[0] = vvx[idx_last];
vvv1_last[1] = vvy[idx_last];
vvv2_last[0] = vvx[idx_last + dir];
vvv2_last[1] = vvy[idx_last + dir];
fillToLast(xx, yy, xd, yd, nc, nr, vvv1, vvv2, vvv1_last,
vvv2_last, (byte) cases[kk], color_bin,
clr_idx[il], color_length, grd_normals, -1,
triStripBldr);
if (!cornerFirst && il == (nn - 1)) {
fillToNearCorner(xx, yy, xd, yd, idx, (byte) cases[kk],
dir, vvx, vvy, nc, nr, crnr_color,
crnrLevelIdx, crnr_out, grd_normals, closed,
triStripBldr);
}
if (cornerFirst && il == (nn - 1)) {
edge_points[0][pt] = vvx[idx + s_idx];
edge_points[1][pt] = vvy[idx + s_idx];
edge_points[0][n_pt] = vvx[idx + ns_idx];
edge_points[1][n_pt] = vvy[idx + ns_idx];
if (clr_idx[il] > cntr_clr)
cntr_clr = clr_idx[il];
}
}
}
}
/*
* Now use edge_points to create the triangle strip to fill the
* remainder of the grid box, ie. the center region.
*/
if (n_crnr_out == 2) { // - don't fill center region
return;
}
if (cntr_color == null) { // - All corners were closed off
cntr_color = new byte[color_length];
for (int c = 0; c < color_length; c++) {
cntr_color[c] = color_bin[c][cntr_clr];
}
}
byte first_tri_orient = 0;
byte last_tri_orient = 0;
byte first_strp_side = SIDE_NONE;
byte last_strp_side = SIDE_NONE;
float[][] normals = null;
if (num_corners == 0) {
tri = new float[2][8];
normals = new float[3][8];
tri[0][0] = edge_points[0][7];
tri[1][0] = edge_points[1][7];
tri[0][1] = edge_points[0][6];
tri[1][1] = edge_points[1][6];
tri[0][2] = edge_points[0][0];
tri[1][2] = edge_points[1][0];
tri[0][3] = edge_points[0][5];
tri[1][3] = edge_points[1][5];
tri[0][4] = edge_points[0][1];
tri[1][4] = edge_points[1][1];
tri[0][5] = edge_points[0][4];
tri[1][5] = edge_points[1][4];
tri[0][6] = edge_points[0][2];
tri[1][6] = edge_points[1][2];
tri[0][7] = edge_points[0][3];
tri[1][7] = edge_points[1][3];
first_strp_side = 3;
last_strp_side = 1;
first_tri_orient = -1;
last_tri_orient = 1;
interpNormals(tri[0], tri[1], xx, yy, nc, nr, xd, yd, grd_normals,
normals);
triStripBldr.addVerticies(cntr_clr, tri, normals, cntr_color,
first_strp_side, first_tri_orient, last_strp_side,
last_tri_orient);
} else if (num_corners == 1) {
tri = new float[2][7];
normals = new float[3][7];
if (which_corner[0] == 1) {
tri[0][0] = edge_points[0][6];
tri[1][0] = edge_points[1][6];
tri[0][1] = edge_points[0][0];
tri[1][1] = edge_points[1][0];
tri[0][2] = edge_points[0][5];
tri[1][2] = edge_points[1][5];
tri[0][3] = edge_points[0][1];
tri[1][3] = edge_points[1][1];
tri[0][4] = edge_points[0][4];
tri[1][4] = edge_points[1][4];
tri[0][5] = edge_points[0][2];
tri[1][5] = edge_points[1][2];
tri[0][6] = edge_points[0][3];
tri[1][6] = edge_points[1][3];
first_strp_side = 3;
last_strp_side = 1;
first_tri_orient = 1;
last_tri_orient = 1;
} else if (which_corner[0] == 2) {
tri[0][0] = edge_points[0][6];
tri[1][0] = edge_points[1][6];
tri[0][1] = edge_points[0][7];
tri[1][1] = edge_points[1][7];
tri[0][2] = edge_points[0][5];
tri[1][2] = edge_points[1][5];
tri[0][3] = edge_points[0][0];
tri[1][3] = edge_points[1][0];
tri[0][4] = edge_points[0][4];
tri[1][4] = edge_points[1][4];
tri[0][5] = edge_points[0][1];
tri[1][5] = edge_points[1][1];
tri[0][6] = edge_points[0][3];
tri[1][6] = edge_points[1][3];
first_strp_side = 3;
last_strp_side = 1;
first_tri_orient = 1;
last_tri_orient = 1;
} else if (which_corner[0] == 7) {
tri[0][0] = edge_points[0][7];
tri[1][0] = edge_points[1][7];
tri[0][1] = edge_points[0][6];
tri[1][1] = edge_points[1][6];
tri[0][2] = edge_points[0][0];
tri[1][2] = edge_points[1][0];
tri[0][3] = edge_points[0][5];
tri[1][3] = edge_points[1][5];
tri[0][4] = edge_points[0][1];
tri[1][4] = edge_points[1][1];
tri[0][5] = edge_points[0][4];
tri[1][5] = edge_points[1][4];
tri[0][6] = edge_points[0][2];
tri[1][6] = edge_points[1][2];
first_strp_side = 3;
last_strp_side = 1;
first_tri_orient = -1;
last_tri_orient = -1;
} else if (which_corner[0] == 4) {
tri[0][0] = edge_points[0][7];
tri[1][0] = edge_points[1][7];
tri[0][1] = edge_points[0][6];
tri[1][1] = edge_points[1][6];
tri[0][2] = edge_points[0][0];
tri[1][2] = edge_points[1][0];
tri[0][3] = edge_points[0][4];
tri[1][3] = edge_points[1][4];
tri[0][4] = edge_points[0][1];
tri[1][4] = edge_points[1][1];
tri[0][5] = edge_points[0][3];
tri[1][5] = edge_points[1][3];
tri[0][6] = edge_points[0][2];
tri[1][6] = edge_points[1][2];
first_strp_side = 3;
last_strp_side = 1;
first_tri_orient = -1;
last_tri_orient = -1;
}
interpNormals(tri[0], tri[1], xx, yy, nc, nr, xd, yd, grd_normals,
normals);
triStripBldr.addVerticies(cntr_clr, tri, normals, cntr_color,
first_strp_side, first_tri_orient, last_strp_side,
last_tri_orient);
} else if (num_corners == 2) {
tri = new float[2][6];
normals = new float[3][6];
int flag = ((which_corner[0] == 1 && which_corner[1] == 7) || (which_corner[0] == 7 && which_corner[1] == 1)) ? 1
: 4;
if (flag == 4) {
tri[0][0] = edge_points[0][6];
tri[1][0] = edge_points[1][6];
tri[0][1] = edge_points[0][7];
tri[1][1] = edge_points[1][7];
tri[0][2] = edge_points[0][4];
tri[1][2] = edge_points[1][4];
tri[0][3] = edge_points[0][0];
tri[1][3] = edge_points[1][0];
tri[0][4] = edge_points[0][3];
tri[1][4] = edge_points[1][3];
tri[0][5] = edge_points[0][1];
tri[1][5] = edge_points[1][1];
first_strp_side = 3;
last_strp_side = 1;
first_tri_orient = 1;
last_tri_orient = -1;
} else if (flag == 1) {
tri[0][0] = edge_points[0][6];
tri[1][0] = edge_points[1][6];
tri[0][1] = edge_points[0][7];
tri[1][1] = edge_points[1][7];
tri[0][2] = edge_points[0][5];
tri[1][2] = edge_points[1][5];
tri[0][3] = edge_points[0][1];
tri[1][3] = edge_points[1][1];
tri[0][4] = edge_points[0][3];
tri[1][4] = edge_points[1][3];
tri[0][5] = edge_points[0][2];
tri[1][5] = edge_points[1][2];
first_strp_side = 3;
last_strp_side = 1;
first_tri_orient = 1;
last_tri_orient = -1;
}
interpNormals(tri[0], tri[1], xx, yy, nc, nr, xd, yd, grd_normals,
normals);
triStripBldr.addVerticies(cntr_clr, tri, normals, cntr_color,
first_strp_side, first_tri_orient, last_strp_side,
last_tri_orient);
}
}
/**
*
* @param xx
* @param yy
* @param xd
* @param yd
* @param v_idx
* @param o_flag
* @param cnt
* @param dir
* @param vx
* @param vy
* @param nc
* @param nr
* @param crnr_color
* @param crnrLevelIdx
* @param crnr_out
* @param grd_normals
* @param closed
* @param triStripBldr
*/
private static void fillToNearCorner(float xx, float yy, float xd,
float yd, int v_idx, byte o_flag, int dir, float[] vx, float[] vy,
int nc, int nr, byte[][] crnr_color, int[] crnrLevelIdx,
boolean[] crnr_out, float[][][] grd_normals, int[] closed,
TriangleStripBuilder triStripBldr) {
float cx = 0;
float cy = 0;
int cc = 0;
int color_length = crnr_color[0].length;
int vidx_0 = 0; // first segment index maps to this in outgoing strip
// array
int vidx_1 = 0; // next " "
int crn = 0; // corner index " "
float[][] normals = new float[3][3];
float[][] tri = new float[2][3];
float[][] tmp = new float[3][1];
byte[] color = new byte[color_length];
byte first_tri_orient = 0;
byte last_tri_orient = 0;
byte first_strp_side = SIDE_NONE;
byte last_strp_side = SIDE_NONE;
switch (o_flag) {
case 1:
cc = 0;
closed[0] = closed[0] | 1;
if (crnr_out[cc])
return;
cx = xx;
cy = yy;
vidx_0 = 2;
vidx_1 = 1;
crn = 0;
normals[0][crn] = grd_normals[nc][nr][0];
normals[1][crn] = grd_normals[nc][nr][1];
normals[2][crn] = grd_normals[nc][nr][2];
first_tri_orient = -1;
last_tri_orient = -1;
first_strp_side = 3;
last_strp_side = 0;
break;
case 4:
cc = 2;
closed[0] = closed[0] | 4;
if (crnr_out[cc])
return;
cx = xx;
cy = yy + yd;
vidx_0 = 0;
vidx_1 = 2;
crn = 1;
normals[0][crn] = grd_normals[nc + 1][nr][0];
normals[1][crn] = grd_normals[nc + 1][nr][1];
normals[2][crn] = grd_normals[nc + 1][nr][2];
first_tri_orient = -1;
last_tri_orient = -1;
first_strp_side = 3;
last_strp_side = 2;
break;
case 2:
cc = 1;
closed[0] = closed[0] | 2;
if (crnr_out[cc])
return;
cx = xx + xd;
cy = yy;
vidx_0 = 0;
vidx_1 = 2;
crn = 1;
normals[0][crn] = grd_normals[nc][nr + 1][0];
normals[1][crn] = grd_normals[nc][nr + 1][1];
normals[2][crn] = grd_normals[nc][nr + 1][2];
first_tri_orient = 1;
last_tri_orient = 1;
first_strp_side = 0;
last_strp_side = 1;
break;
case 7:
cc = 3;
closed[0] = closed[0] | 8;
if (crnr_out[cc])
return;
cx = xx + xd;
cy = yy + yd;
vidx_0 = 2;
vidx_1 = 0;
crn = 1;
normals[0][crn] = grd_normals[nc + 1][nr + 1][0];
normals[1][crn] = grd_normals[nc + 1][nr + 1][1];
normals[2][crn] = grd_normals[nc + 1][nr + 1][2];
first_tri_orient = -1;
last_tri_orient = -1;
first_strp_side = 2;
last_strp_side = 1;
break;
}
for (int ii = 0; ii < color_length; ii++) {
color[ii] = crnr_color[cc][ii];
}
int levIdx = crnrLevelIdx[cc];
tri[0][crn] = cx;
tri[1][crn] = cy;
tri[0][vidx_0] = vx[v_idx];
tri[1][vidx_0] = vy[v_idx];
interpNormals(tri[0][vidx_0], tri[1][vidx_0], xx, yy, nc, nr, xd, yd,
grd_normals, tmp);
normals[0][vidx_0] = tmp[0][0];
normals[1][vidx_0] = tmp[1][0];
normals[2][vidx_0] = tmp[2][0];
tri[0][vidx_1] = vx[v_idx + dir];
tri[1][vidx_1] = vy[v_idx + dir];
interpNormals(tri[0][vidx_1], tri[1][vidx_1], xx, yy, nc, nr, xd, yd,
grd_normals, tmp);
normals[0][vidx_1] = tmp[0][0];
normals[1][vidx_1] = tmp[1][0];
normals[2][vidx_1] = tmp[2][0];
triStripBldr.addVerticies(levIdx, tri, normals, color, first_strp_side,
first_tri_orient, last_strp_side, last_tri_orient);
}
/**
*
* @param xx
* @param yy
* @param xd
* @param yd
* @param v_idx
* @param o_flag
* @param dir
* @param vx
* @param vy
* @param nc
* @param nr
* @param crnr_color
* @param crnrLevelIdx
* @param crnr_out
* @param grd_normals
* @param closed
* @param triStripBldr
*/
private static void fillToOppCorner(float xx, float yy, float xd, float yd,
int v_idx, byte o_flag, int dir, float[] vx, float[] vy, int nc,
int nr, byte[][] crnr_color, int[] crnrLevelIdx,
boolean[] crnr_out, float[][][] grd_normals, int[] closed,
TriangleStripBuilder triStripBldr) {
float cx1 = 0;
float cx2 = 0;
float cx3 = 0;
float cy1 = 0;
float cy2 = 0;
float cy3 = 0;
int cc = 0;
int[][] grd = new int[3][2];
int color_length = crnr_color[0].length;
float[][] tri = new float[2][5];
float[][] normals = new float[3][5];
float[][] tmp = new float[3][1];
byte[] color = new byte[color_length];
int vidx_0 = 0; // first segment index maps to this in outgoing strip
// array
int vidx_1 = 0; // next " "
int crn_1 = 0; // corner's index into outgoing strip array
int crn_2 = 0; // " "
int crn_3 = 0; // " "
byte first_tri_orient = 0;
byte last_tri_orient = 0;
byte first_strp_side = SIDE_NONE;
byte last_strp_side = SIDE_NONE;
switch (o_flag) {
case 1:
closed[0] = closed[0] | 14;
if (crnr_out[1] || crnr_out[2] || crnr_out[3])
return;
cx1 = xx + xd;
cy1 = yy;
cx2 = xx + xd;
cy2 = yy + yd;
cx3 = xx;
cy3 = yy + yd;
cc = 3;
grd[0][0] = 1;
grd[0][1] = 0;
grd[1][0] = 1;
grd[1][1] = 1;
grd[2][0] = 0;
grd[2][1] = 1;
vidx_0 = 2;
vidx_1 = 0;
crn_1 = 4;
crn_2 = 3;
crn_3 = 1;
first_tri_orient = -1;
last_tri_orient = -1;
first_strp_side = 3;
last_strp_side = 1;
break;
case 2:
closed[0] = closed[0] | 13;
if (crnr_out[0] || crnr_out[2] || crnr_out[3])
return;
cx1 = xx;
cy1 = yy;
cx2 = xx;
cy2 = yy + yd;
cx3 = xx + xd;
cy3 = yy + yd;
cc = 2;
grd[0][0] = 0;
grd[0][1] = 0;
grd[1][0] = 0;
grd[1][1] = 1;
grd[2][0] = 1;
grd[2][1] = 1;
vidx_0 = 2;
vidx_1 = 4;
crn_1 = 0;
crn_2 = 1;
crn_3 = 3;
first_tri_orient = -1;
last_tri_orient = -1;
first_strp_side = 3;
last_strp_side = 1;
break;
case 4:
closed[0] = closed[0] | 11;
if (crnr_out[0] || crnr_out[1] || crnr_out[3])
return;
cx1 = xx;
cy1 = yy;
cx2 = xx + xd;
cy2 = yy;
cx3 = xx + xd;
cy3 = yy + yd;
cc = 1;
grd[0][0] = 0;
grd[0][1] = 0;
grd[1][0] = 1;
grd[1][1] = 0;
grd[2][0] = 1;
grd[2][1] = 1;
vidx_0 = 1;
vidx_1 = 3;
crn_1 = 0;
crn_2 = 2;
crn_3 = 4;
first_tri_orient = -1;
last_tri_orient = -1;
first_strp_side = 3;
last_strp_side = 2;
break;
case 7:
closed[0] = closed[0] | 7;
if (crnr_out[0] || crnr_out[1] || crnr_out[2])
return;
cx1 = xx + xd;
cy1 = yy;
cx2 = xx;
cy2 = yy;
cx3 = xx;
cy3 = yy + yd;
cc = 0;
grd[0][0] = 1;
grd[0][1] = 0;
grd[1][0] = 0;
grd[1][1] = 0;
grd[2][0] = 0;
grd[2][1] = 1;
vidx_0 = 4;
vidx_1 = 3;
crn_1 = 2;
crn_2 = 0;
crn_3 = 1;
first_tri_orient = -1;
last_tri_orient = -1;
first_strp_side = 3;
last_strp_side = 1;
break;
}
for (int ii = 0; ii < color_length; ii++) {
color[ii] = crnr_color[cc][ii];
}
int levIdx = crnrLevelIdx[cc];
tri[0][crn_1] = cx1;
tri[1][crn_1] = cy1;
normals[0][crn_1] = grd_normals[nc + grd[0][1]][nr + grd[0][0]][0];
normals[1][crn_1] = grd_normals[nc + grd[0][1]][nr + grd[0][0]][1];
normals[2][crn_1] = grd_normals[nc + grd[0][1]][nr + grd[0][0]][2];
tri[0][crn_2] = cx2;
tri[1][crn_2] = cy2;
normals[0][crn_2] = grd_normals[nc + grd[1][1]][nr + grd[1][0]][0];
normals[1][crn_2] = grd_normals[nc + grd[1][1]][nr + grd[1][0]][1];
normals[2][crn_2] = grd_normals[nc + grd[1][1]][nr + grd[1][0]][2];
tri[0][crn_3] = cx3;
tri[1][crn_3] = cy3;
normals[0][crn_3] = grd_normals[nc + grd[2][1]][nr + grd[2][0]][0];
normals[1][crn_3] = grd_normals[nc + grd[2][1]][nr + grd[2][0]][1];
normals[2][crn_3] = grd_normals[nc + grd[2][1]][nr + grd[2][0]][2];
tri[0][vidx_0] = vx[v_idx];
tri[1][vidx_0] = vy[v_idx];
interpNormals(tri[0][vidx_0], tri[1][vidx_0], xx, yy, nc, nr, xd, yd,
grd_normals, tmp);
normals[0][vidx_0] = tmp[0][0];
normals[1][vidx_0] = tmp[1][0];
normals[2][vidx_0] = tmp[2][0];
tri[0][vidx_1] = vx[v_idx + dir];
tri[1][vidx_1] = vy[v_idx + dir];
interpNormals(tri[0][vidx_1], tri[1][vidx_1], xx, yy, nc, nr, xd, yd,
grd_normals, tmp);
normals[0][vidx_1] = tmp[0][0];
normals[1][vidx_1] = tmp[1][0];
normals[2][vidx_1] = tmp[2][0];
triStripBldr.addVerticies(levIdx, tri, normals, color, first_strp_side,
first_tri_orient, last_strp_side, last_tri_orient);
}
/**
*
* @param xx
* @param yy
* @param xd
* @param yd
* @param v_idx
* @param o_flag
* @param flag
* @param cnt
* @param dir
* @param vx
* @param vy
* @param nc
* @param nr
* @param crnr_color
* @param crnrLevelIdx
* @param crnr_out
* @param grd_normals
* @param closed
* @param triStripBldr
*/
private static void fillToSide(float xx, float yy, float xd, float yd,
int v_idx, byte o_flag, int flag, int dir, float[] vx, float[] vy,
int nc, int nr, byte[][] crnr_color, int[] crnrLevelIdx,
boolean[] crnr_out, float[][][] grd_normals, int[] closed,
TriangleStripBuilder triStripBldr) {
float[][] tri = new float[2][4];
float[][] normals = new float[3][4];
fillToSide(xx, yy, xd, yd, v_idx, o_flag, flag, dir, vx, vy, nc, nr,
crnr_color, crnrLevelIdx, crnr_out, grd_normals, closed, tri,
normals, triStripBldr);
}
private static void fillToSide(float xx, float yy, float xd, float yd,
int v_idx, byte o_flag, int flag, int dir, float[] vx, float[] vy,
int nc, int nr, byte[][] crnr_color, int[] crnrLevelIdx,
boolean[] crnr_out, float[][][] grd_normals, int[] closed,
float[][] strpverts, float[][] strpnrmls,
TriangleStripBuilder triStripBldr) {
float cx1 = 0;
float cy1 = 0;
float cx2 = 0;
float cy2 = 0;
int cc = 0;
int[][] grd = new int[2][2];
int color_length = crnr_color[0].length;
float[][] tri = new float[2][4];
float[][] normals = new float[3][4];
float[][] tmp = new float[3][1];
byte[] color = new byte[color_length];
int vidx_0 = 0;
int vidx_1 = 0;
int crn_1 = 0;
int crn_2 = 0;
byte first_tri_orient = 0;
byte last_tri_orient = 0;
byte first_strp_side = SIDE_NONE;
byte last_strp_side = SIDE_NONE;
switch (o_flag) {
case 3:
switch (flag) {
case 1:
closed[0] = closed[0] | 12;
if (crnr_out[2] || crnr_out[3])
return;
cx1 = xx;
cy1 = yy + yd;
cx2 = xx + xd;
cy2 = yy + yd;
cc = 3;
grd[0][0] = 0;
grd[0][1] = 1;
grd[1][0] = 1;
grd[1][1] = 1;
crn_1 = 1;
crn_2 = 3;
vidx_0 = 0;
vidx_1 = 2;
first_tri_orient = -1;
last_tri_orient = 1;
first_strp_side = 3;
last_strp_side = 1;
break;
case -1:
closed[0] = closed[0] | 3;
if (crnr_out[0] || crnr_out[1])
return;
cx1 = xx;
cy1 = yy;
cx2 = xx + xd;
cy2 = yy;
cc = 0;
grd[0][0] = 0;
grd[0][1] = 0;
grd[1][0] = 1;
grd[1][1] = 0;
crn_1 = 0;
crn_2 = 2;
vidx_0 = 1;
vidx_1 = 3;
first_tri_orient = -1;
last_tri_orient = 1;
first_strp_side = 3;
last_strp_side = 1;
break;
}
break;
case 5:
switch (flag) {
case 1:
closed[0] = closed[0] | 5;
if (crnr_out[0] || crnr_out[2])
return;
cx1 = xx;
cy1 = yy;
cx2 = xx;
cy2 = yy + yd;
cc = 0;
grd[0][0] = 0;
grd[0][1] = 0;
grd[1][0] = 0;
grd[1][1] = 1;
crn_1 = 0;
crn_2 = 1;
vidx_0 = 2;
vidx_1 = 3;
first_tri_orient = -1;
last_tri_orient = 1;
first_strp_side = 3;
last_strp_side = -1;
break;
case -1:
closed[0] = closed[0] | 10;
if (crnr_out[1] || crnr_out[3])
return;
cx1 = xx + xd;
cy1 = yy;
cx2 = xx + xd;
cy2 = yy + yd;
grd[0][0] = 1;
grd[0][1] = 0;
grd[1][0] = 1;
grd[1][1] = 1;
cc = 3;
crn_1 = 2;
crn_2 = 3;
vidx_0 = 0;
vidx_1 = 1;
first_tri_orient = -1;
last_tri_orient = 1;
first_strp_side = -1;
last_strp_side = 1;
break;
}
break;
}
for (int ii = 0; ii < color_length; ii++) {
color[ii] = crnr_color[cc][ii];
}
int levIdx = crnrLevelIdx[cc];
tri[0][crn_1] = cx1;
tri[1][crn_1] = cy1;
int i = grd[0][0];
int j = grd[0][1];
normals[0][crn_1] = grd_normals[nc + j][nr + i][0];
normals[1][crn_1] = grd_normals[nc + j][nr + i][1];
normals[2][crn_1] = grd_normals[nc + j][nr + i][2];
tri[0][crn_2] = cx2;
tri[1][crn_2] = cy2;
i = grd[1][0];
j = grd[1][1];
normals[0][crn_2] = grd_normals[nc + j][nr + i][0];
normals[1][crn_2] = grd_normals[nc + j][nr + i][1];
normals[2][crn_2] = grd_normals[nc + j][nr + i][2];
tri[0][vidx_0] = vx[v_idx];
tri[1][vidx_0] = vy[v_idx];
interpNormals(tri[0][vidx_0], tri[1][vidx_0], xx, yy, nc, nr, xd, yd,
grd_normals, tmp);
normals[0][vidx_0] = tmp[0][0];
normals[1][vidx_0] = tmp[1][0];
normals[2][vidx_0] = tmp[2][0];
tri[0][vidx_1] = vx[v_idx + dir];
tri[1][vidx_1] = vy[v_idx + dir];
interpNormals(tri[0][vidx_1], tri[1][vidx_1], xx, yy, nc, nr, xd, yd,
grd_normals, tmp);
normals[0][vidx_1] = tmp[0][0];
normals[1][vidx_1] = tmp[1][0];
normals[2][vidx_1] = tmp[2][0];
if (triStripBldr != null) {
triStripBldr.addVerticies(levIdx, tri, normals, color,
first_strp_side, first_tri_orient, last_strp_side,
last_tri_orient);
}
}
private static void addCorner(float xx, float yy, float xd, float yd,
int nc, int nr, byte cornerID, float[][][] grd_normals,
int[] closed, int strpIdx, float[][] strpverts, float[][] strpnrmls) {
float cx = 0;
float cy = 0;
int i = 0; // int offsets for corners
int j = 0;
if (cornerID == 0) {
closed[0] = closed[0] | 1;
cx = xx;
cy = yy;
i = 0;
j = 0;
} else if (cornerID == 1) {
closed[0] = closed[0] | 2;
cx = xx + xd;
cy = yy;
i = 1;
j = 0;
} else if (cornerID == 2) {
closed[0] = closed[0] | 4;
cx = xx;
cy = yy + yd;
i = 0;
j = 1;
} else if (cornerID == 3) {
closed[0] = closed[0] | 8;
cx = xx + xd;
cy = yy + yd;
i = 1;
j = 1;
}
strpverts[0][strpIdx] = cx;
strpverts[1][strpIdx] = cy;
strpnrmls[0][strpIdx] = grd_normals[nc + j][nr + i][0];
strpnrmls[1][strpIdx] = grd_normals[nc + j][nr + i][1];
strpnrmls[2][strpIdx] = grd_normals[nc + j][nr + i][2];
}
public static int[] getTriOrientation(float[][] verts) {
/* note: doesn't deal with cross-product == 0 */
int len = verts[0].length;
float xa = verts[0][1] - verts[0][0];
float ya = verts[1][1] - verts[1][0];
float xb = verts[0][2] - verts[0][0];
float yb = verts[1][2] - verts[1][0];
float first = xa * yb - xb * ya;
xa = verts[0][len - 2] - verts[0][len - 3];
ya = verts[1][len - 2] - verts[1][len - 3];
xb = verts[0][len - 1] - verts[0][len - 3];
yb = verts[1][len - 1] - verts[1][len - 3];
float last = xa * yb - xb * ya;
int firstOrient = (first < 0) ? CLOCKWISE : CNTRCLOCKWISE;
int lastOrient = (last < 0) ? CLOCKWISE : CNTRCLOCKWISE;
return new int[] { firstOrient, lastOrient };
}
static final class ContourOutput {
public final ContourStripSet stripSet;
public final TriangleStripBuilder triStripBldr;
ContourOutput(ContourStripSet set, TriangleStripBuilder tsb) {
stripSet = set;
triStripBldr = tsb;
}
boolean isLineStyled(int lvl) {
return stripSet.isLevelStyled(lvl);
}
List<float[][][]> getLineStripCoordinates(int lvl) {
return stripSet.getLineStripCoordinates(lvl);
}
List<byte[][][]> getLineStripColors(int lvl) {
return stripSet.getLineStripColors(lvl);
}
int getIntervalCount() {
return stripSet.vecArray.length;
}
List<ContourStrip> getStrips(int lvl) {
return stripSet.vecArray[lvl];
}
int[] getLabelIndexes(int lvlIdx) {
return stripSet.labelIndexes[lvlIdx];
}
float[] getLevels() {
return stripSet.levels;
}
}
} // end class
/**
* Class ContourQuadSet
*
*/
class ContourQuadSet {
/** */
int nx = 1;
/** */
int ny = 1;
/** */
int npx;
/** */
int npy;
/** */
int nc;
/** */
int nr;
/** */
int lev_idx;
/** */
int numv = 0;
/** */
ContourStripSet css = null;
/** */
ContourQuad[][] qarray = null;
/** */
int snumv = 0;
/** */
public Map<CachedArrayDimension, CachedArray> subGridMap = new HashMap<CachedArrayDimension, CachedArray>();
/** */
public Map<CachedArrayDimension, CachedArray> subGrid2Map = new HashMap<CachedArrayDimension, CachedArray>();
/** */
public Map<CachedArrayDimension, CachedArray> markGridMap = new HashMap<CachedArrayDimension, CachedArray>();
/** */
public Map<CachedArrayDimension, CachedArray> markGrid2Map = new HashMap<CachedArrayDimension, CachedArray>();
/**
*
* @param nr
* @param nc
* @param lev_idx
* @param css
*/
ContourQuadSet(int nr, int nc, int lev_idx, ContourStripSet css) {
this.nc = nc;
this.nr = nr;
this.lev_idx = lev_idx;
this.css = css;
npy = (int) (nr / ny);
npx = (int) (nc / nx);
qarray = new ContourQuad[ny][nx];
// JDM: Only make the ContourQuad objects when we need them
/*
* for (int j=0; j<ny; j++) { for (int i=0; i<nx; i++) { qarray[j][i] =
* makeContourQuad(j,i); } }
*/
}
/**
*
* @param j
* @param i
*
* @return
*/
private ContourQuad makeContourQuad(int j, int i) {
int lenx = npx;
int leny = npy;
if (j == ny - 1)
leny = nr - (ny - 1) * npy;
if (i == nx - 1)
lenx = nc - (nx - 1) * npx;
return new ContourQuad(this, j * npy, i * npx, leny, lenx);
}
/**
*
* @param idx0
* @param ir
* @param ic
*/
public void add(int idx0, int ir, int ic) {
int ix = (int) (ic / npx);
int iy = (int) (ir / npy);
if (ix >= nx)
ix = nx - 1;
if (iy >= ny)
iy = ny - 1;
if (qarray[iy][ix] == null) {
qarray[iy][ix] = makeContourQuad(iy, ix);
}
qarray[iy][ix].add(idx0, ir, ic);
}
/**
*
* @param vx
* @param vy
*/
public void get(float[] vx, float[] vy) {
numv = 0;
snumv = 0;
for (int j = 0; j < ny; j++) {
for (int i = 0; i < nx; i++) {
if (qarray[j][i] == null)
continue;
ContourStrip[] c_strps = qarray[j][i].getContourStrips(vx, vy);
numv += qarray[j][i].numv;
snumv += qarray[j][i].stripCnt;
if (c_strps != null) {
css.vecArray[lev_idx].add(c_strps[0]);
}
}
}
}
/**
*
* @param vx
* @param vy
* @param auxLevels
* @param vx1
* @param vy1
* @param vz1
* @param colors
* @param spatial_set
*
* @throws VisADException
*/
public void getArrays(float[] vx, float[] vy, byte[][] auxLevels,
float[][] vx1, float[][] vy1, float[][] vz1, byte[][] colors,
Gridded3DSet spatial_set) throws VisADException {
float[][] arrays = new float[2][2 * numv];
int clr_dim = 3;
if (auxLevels != null) {
clr_dim = auxLevels.length;
colors[0] = new byte[2 * numv];
colors[1] = new byte[2 * numv];
colors[2] = new byte[2 * numv];
colors[3] = new byte[2 * numv];
}
int cnt = 0;
for (int j = 0; j < ny; j++) {
for (int i = 0; i < nx; i++) {
if (qarray[j][i] == null)
continue;
for (int k = 0; k < qarray[j][i].numv; k++) {
int vidx = qarray[j][i].vert_indices[k];
if (vidx >= 0) {
arrays[0][cnt] = vx[vidx];
arrays[1][cnt] = vy[vidx];
if (auxLevels != null) {
colors[0][cnt] = auxLevels[0][vidx];
colors[1][cnt] = auxLevels[1][vidx];
colors[2][cnt] = auxLevels[2][vidx];
if (clr_dim == 4)
colors[3][cnt] = auxLevels[3][vidx];
}
cnt++;
arrays[0][cnt] = vx[vidx + 1];
arrays[1][cnt] = vy[vidx + 1];
if (auxLevels != null) {
colors[0][cnt] = auxLevels[0][vidx + 1];
colors[1][cnt] = auxLevels[1][vidx + 1];
colors[2][cnt] = auxLevels[2][vidx + 1];
if (clr_dim == 4)
colors[3][cnt] = auxLevels[3][vidx];
}
cnt++;
}
}
}
}
float[][] tmp = new float[2][cnt];
System.arraycopy(arrays[0], 0, tmp[0], 0, cnt);
System.arraycopy(arrays[1], 0, tmp[1], 0, cnt);
float[][] tmp3D = spatial_set.gridToValue(tmp);
vx1[0] = tmp3D[0];
vy1[0] = tmp3D[1];
vz1[0] = tmp3D[2];
arrays = null;
colors = null;
}
}
/**
* Class ContourQuad
*
*/
class ContourQuad {
/** */
int[] vert_indices;
/** */
int[] vert_indices_save = null;
/** */
int[] grid_indices;
/** */
int maxnumv;
/** */
int numv;
/** */
ContourQuadSet qs;
/** */
int nc;
/** */
int nr;
/** */
int strty;
/** */
int strtx;
/** */
int leny;
/** */
int lenx;
/** */
int lev_idx;
/** */
int[][] sub_grid = null;
/** */
int[][] sub_grid_2 = null;
/** */
int[][] mark_grid = null;
/** */
int[][] mark_grid_2 = null;
/** */
ContourStripSet css = null;
/** */
int[] stripVert_indices;
/** */
int stripCnt = 0;
/**
*
* @param qs
* @param strty
* @param strtx
* @param leny
* @param lenx
*/
ContourQuad(ContourQuadSet qs, int strty, int strtx, int leny, int lenx) {
maxnumv = 100;
numv = 0;
vert_indices = new int[maxnumv]; // - indices into vx,vy
grid_indices = new int[maxnumv]; // - location on the grid
this.qs = qs;
this.nc = qs.nc;
this.nr = qs.nr;
this.strty = strty;
this.strtx = strtx;
this.leny = leny;
this.lenx = lenx;
css = qs.css;
lev_idx = qs.lev_idx;
}
/**
*
* @param idx0
* @param gy
* @param gx
*/
public void add(int idx0, int gy, int gx) {
if (numv < maxnumv - 2) {
vert_indices[numv] = idx0;
grid_indices[numv] = gy * nc + gx;
numv++;
} else {
maxnumv += 50;
int[] tmpA = vert_indices;
int[] tmpB = grid_indices;
vert_indices = new int[maxnumv];
grid_indices = new int[maxnumv];
System.arraycopy(tmpA, 0, vert_indices, 0, numv);
System.arraycopy(tmpB, 0, grid_indices, 0, numv);
tmpA = null;
tmpB = null;
vert_indices[numv] = idx0;
grid_indices[numv] = gy * nc + gx;
numv++;
}
}
/**
*
* @param leny
* @param lenx
*
* @return
*/
public int[][][] getWorkArrays(int leny, int lenx) {
Object key;
java.util.Set<CachedArrayDimension> keySet = qs.subGridMap.keySet();
key = null;
for (CachedArrayDimension obj : keySet) {
if (obj.equals(new CachedArrayDimension(leny, lenx))) {
key = obj;
break;
}
}
int[][] subgrid = null;
int[][] subgrid2 = null;
int[][] markgrid = null;
int[][] markgrid2 = null;
if (key != null) {
subgrid = ((CachedArray) qs.subGridMap.get(key)).getArray();
subgrid2 = ((CachedArray) qs.subGrid2Map.get(key)).getArray();
markgrid = ((CachedArray) qs.markGridMap.get(key)).getArray();
markgrid2 = ((CachedArray) qs.markGrid2Map.get(key)).getArray();
} else {
subgrid = new int[leny][lenx];
subgrid2 = new int[leny][lenx];
markgrid = new int[leny][lenx];
markgrid2 = new int[leny][lenx];
CachedArrayDimension newKey = new CachedArrayDimension(leny, lenx);
qs.subGridMap.put(newKey, new CachedArray(subgrid));
qs.subGrid2Map.put(newKey, new CachedArray(subgrid2));
qs.markGridMap.put(newKey, new CachedArray(markgrid));
qs.markGrid2Map.put(newKey, new CachedArray(markgrid2));
}
return new int[][][] { subgrid, subgrid2, markgrid, markgrid2 };
}
/**
*
*/
public void get() {
int ix_i = -1;
int iy_i = -1;
int[][][] workarrays = getWorkArrays(leny, lenx);
sub_grid = workarrays[0];
sub_grid_2 = workarrays[1];
mark_grid = workarrays[2];
mark_grid_2 = workarrays[3];
for (int j = 0; j < leny; j++) {
for (int i = 0; i < lenx; i++) {
sub_grid[j][i] = 0;
sub_grid_2[j][i] = 0;
}
}
if (vert_indices_save == null) {
vert_indices_save = new int[vert_indices.length];
System.arraycopy(vert_indices, 0, vert_indices_save, 0,
vert_indices.length);
} else {
System.arraycopy(vert_indices_save, 0, vert_indices, 0,
vert_indices.length);
}
for (int ii = 0; ii < numv; ii++) {
int kk = grid_indices[ii];
int iy = (int) kk / nc;
int ix = kk - iy * nc;
sub_grid[iy - strty][ix - strtx] = vert_indices[ii];
mark_grid[iy - strty][ix - strtx] = ii;
if (ix_i == ix && iy_i == iy) {
sub_grid_2[iy - strty][ix - strtx] = vert_indices[ii];
mark_grid_2[iy - strty][ix - strtx] = ii;
}
ix_i = ix;
iy_i = iy;
}
}
/**
*
*/
public void reset() {
for (int j = 0; j < leny; j++) {
for (int i = 0; i < lenx; i++) {
if (sub_grid[j][i] < 0) {
sub_grid[j][i] *= -1;
}
}
}
}
/**
*
* @param vx
* @param vy
*
* @return
*/
public ContourStrip[] getContourStrips(float[] vx, float[] vy) {
get();
stripVert_indices = new int[200];
int n_segs = 0;
int[][] udrl = { { 1, -1, 0, 0 }, { 0, 0, 1, -1 } }; // -up/down,
// right/left
// - find starting point
int[] start = getStartPoint();
if (start == null) {
return null;
}
int iy = start[0];
int ix = start[1];
int idx0 = sub_grid[iy][ix];
int idx1 = idx0 + 1;
ContourStrip c_strp = new ContourStrip(lev_idx, idx0, idx1, css);
int idxA = idx0;
int idxB = idx0;
int idxA_2;
int idxB_2;
int ix_t, iy_t;
int ix_a = ix;
int iy_a = iy;
int ix_b = ix;
int iy_b = iy;
int cnt = 0;
stripVert_indices[cnt++] = idx0;
sub_grid[iy][ix] *= -1;
int test_cnt = 0;
while ((n_segs < 100) && (test_cnt < 300)) {
test_cnt++;
// - A
for (int k = 0; k < 4; k++) {
ix_t = ix_a + udrl[0][k];
iy_t = iy_a + udrl[1][k];
if ((iy_t >= 0 && iy_t < leny) && (ix_t >= 0 && ix_t < lenx)) {
idxA = sub_grid[iy_t][ix_t];
idxA_2 = sub_grid_2[iy_t][ix_t];
if (idxA > 0) {
if (c_strp.addPair(vx, vy, idxA, idxA + 1)) {
sub_grid[iy_t][ix_t] *= -1;
stripVert_indices[cnt++] = idxA;
ix_a = ix_t;
iy_a = iy_t;
vert_indices[mark_grid[iy_t][ix_t]] = -1;
n_segs++;
break;
}
}
if (idxA_2 > 0) {
if (c_strp.addPair(vx, vy, idxA_2, idxA_2 + 1)) {
sub_grid_2[iy_t][ix_t] *= -1;
stripVert_indices[cnt++] = idxA_2;
ix_a = ix_t;
iy_a = iy_t;
vert_indices[mark_grid_2[iy_t][ix_t]] = -1;
n_segs++;
break;
}
}
}
}
// - B
for (int k = 0; k < 4; k++) {
ix_t = ix_b + udrl[0][k];
iy_t = iy_b + udrl[1][k];
if ((iy_t >= 0 && iy_t < leny) && (ix_t >= 0 && ix_t < lenx)) {
idxB = sub_grid[iy_t][ix_t];
idxB_2 = sub_grid_2[iy_t][ix_t];
if (idxB > 0) {
if (c_strp.addPair(vx, vy, idxB, idxB + 1)) {
sub_grid[iy_t][ix_t] *= -1;
stripVert_indices[cnt++] = idxB;
ix_b = ix_t;
iy_b = iy_t;
vert_indices[mark_grid[iy_t][ix_t]] = -1;
n_segs++;
break;
}
}
if (idxB_2 > 0) {
if (c_strp.addPair(vx, vy, idxB_2, idxB_2 + 1)) {
sub_grid_2[iy_t][ix_t] *= -1;
stripVert_indices[cnt++] = idxB_2;
ix_b = ix_t;
iy_b = iy_t;
vert_indices[mark_grid_2[iy_t][ix_t]] = -1;
n_segs++;
break;
}
}
}
}
}
stripCnt = cnt;
sub_grid = null;
sub_grid_2 = null;
return new ContourStrip[] { c_strp };
}
/**
* getStartPoint
*
* @return Starting point as two-element int array
*/
public int[] getStartPoint() {
int n_trys = 20;
float nn = (float) lenx * leny;
java.util.Random rnd = new java.util.Random();
for (int tt = 0; tt < n_trys; tt++) {
int kk = (int) (nn * rnd.nextFloat());
int j = (int) kk / lenx;
int i = kk - j * lenx;
if (sub_grid[j][i] != 0) {
return new int[] { j, i };
}
}
return null;
}
}
/**
* Class CachedArray
*
*/
class CachedArray {
/** */
int[][] array;
/**
*
*
* @param array
*/
public CachedArray(int[][] array) {
this.array = array;
}
/**
*
*
* @return
*/
int[][] getArray() {
return array;
}
}
/**
* Class CachedArrayDimension
*
*/
class CachedArrayDimension {
/** */
int lenx;
/** */
int leny;
/**
*
*
* @param leny
* @param lenx
*/
CachedArrayDimension(int leny, int lenx) {
this.leny = leny;
this.lenx = lenx;
}
/**
*
*
* @param obj
*
* @return
*/
public boolean equals(CachedArrayDimension obj) {
return (lenx == obj.lenx && leny == obj.leny);
}
}
/**
* ContourStripSet is used internally by Contour2D
*/
class ContourStripSet {
// value for dash algm.
/** */
static final int DEFAULT_DASH_VALUE = 2;
/** */
static final int DISABLE_DASH_VALUE = -1;
/** */
float[] levels;
int[][] labelIndexes;
int labelFreq = ContourControl.LABEL_FREQ_LO;
/** */
int n_levs;
/** */
int nr;
/** */
int nc;
/** */
Gridded3DSet spatial_set;
/** Contour strips by level. */
List<ContourStrip>[] vecArray;
/** */
List<ContourStrip> vec;
/** Closed strips by level. */
List<ContourStrip>[] closedStripArray;
List<ContourStrip> closedStripList;
/** */
boolean[] swap;
/** */
ContourQuadSet[] qSet;
/** Grid X coordinates. */
private float[] gridX;
/** Grid Y coordinates. */
private float[] gridY;
/** Colors corresponding to grid values. */
private byte[][] gridColors;
ArrayList<ContourLabelGeometry> labels = new ArrayList<ContourLabelGeometry>();
ArrayList<VisADLineStripArray> fillLines = new ArrayList<VisADLineStripArray>();
ArrayList<VisADLineStripArray> fillLinesStyled = new ArrayList<VisADLineStripArray>();
ArrayList<VisADLineStripArray> cntrLines = new ArrayList<VisADLineStripArray>();
ArrayList<VisADLineStripArray> cntrLinesStyled = new ArrayList<VisADLineStripArray>();
double labelScale;
public int labelLineSkip = ContourControl.EVERY_NTH_DEFAULT;
/**
*
* @param levels
* @param swap
* @param scale_ratio
* @param label_size
* @param nr
* @param nc
* @param spatial_set
* @param contourDifficulty
*
* @throws VisADException
*/
ContourStripSet(float[] levels, boolean[] swap, double scale_ratio,
int label_freq, int label_line_skip, double label_size, int nr, int nc,
Gridded3DSet spatial_set) throws VisADException {
this.levels = levels;
n_levs = levels.length;
labelIndexes = new int[n_levs][];
labelFreq = label_freq;
labelLineSkip = label_line_skip;
vecArray = new List[n_levs];
closedStripArray = new List[n_levs];
labelScale = ((0.062 * (1.0 / scale_ratio)) * label_size);
this.nr = nr;
this.nc = nc;
this.swap = swap;
this.spatial_set = spatial_set;
for (int kk = 0; kk < n_levs; kk++) {
vecArray[kk] = new ArrayList<ContourStrip>();
closedStripArray[kk] = new ArrayList<ContourStrip>();
}
qSet = new ContourQuadSet[n_levs];
for (int kk = 0; kk < n_levs; kk++) {
qSet[kk] = new ContourQuadSet(nr, nc, kk, this);
}
}
/**
* Set the grid coordinates used to contruct <code>ContourStrip</code>s
* contained in this set.
*
* @param gx
* @param gy
*/
void setGridValues(float[] gx, float[] gy) {
gridX = gx;
gridY = gy;
}
void setGridColors(byte[][] colors) {
gridColors = colors;
}
/**
*
* @param vx
* @param vy
* @param idx0
* @param idx1
* @param lev_idx
* @param ir
* @param ic
*/
void add(float[] vx, float[] vy, int idx0, int idx1, int lev_idx, int ir,
int ic) {
qSet[lev_idx].add(idx0, ir, ic);
}
/**
*
* @param vx
* @param vy
* @param idx0
* @param idx1
* @param level
*/
void add(float[] vx, float[] vy, int idx0, int idx1, float level) {
int lev_idx = 0;
for (int kk = 0; kk < n_levs; kk++) {
if (level == levels[kk])
lev_idx = kk;
}
add(vx, vy, idx0, idx1, lev_idx);
}
/**
*
* @param vx
* @param vy
* @param idx0
* @param idx1
* @param lev_idx
*/
void add(float[] vx, float[] vy, int idx0, int idx1, int lev_idx) {
float delx = vx[idx1] - vx[idx0];
float dely = vy[idx1] - vy[idx0];
// skip really small segments
if ((delx <= 0.0001 && delx >= -0.0001) && (dely <= 0.0001 && dely >= -0.0001)) {
return;
}
vec = vecArray[lev_idx];
closedStripList = closedStripArray[lev_idx];
int n_strip = vec.size();
if (n_strip == 0) {
ContourStrip c_strp = new ContourStrip(lev_idx, idx0, idx1, this);
vec.add(c_strp);
} else {
int[] found_array = new int[3];
int found = 0;
for (int kk = 0; kk < n_strip; kk++) {
ContourStrip c_strp = vec.get(kk);
if (c_strp.addPair(vx, vy, idx0, idx1)) {
found_array[found] = kk;
found++;
if (c_strp.closed) { // take off main list, add to closed (done) list.
vec.remove(c_strp);
closedStripList.add(c_strp);
break;
}
// exit loop if we hit threshold value
if (found == 3) break;
}
}
if (found == 3) {
ContourStrip c_strp = new ContourStrip(lev_idx, idx0,
idx1, this);
vec.add(c_strp);
} else if (found == 2) {
ContourStrip c_strpA = vec.get(found_array[0]);
ContourStrip c_strpB = vec.get(found_array[1]);
c_strpA.merge(c_strpB);
vec.remove(found_array[1]);
} else if (found == 0) {
ContourStrip c_strp = new ContourStrip(lev_idx, idx0,
idx1, this);
vec.add(c_strp);
}
}
}
/**
* Iterates over list of ContourStrips for each contour level index.
*
*
* @param vx
* Grid coordinate values.
* @param vy
* Grid coordinate values.
* @param colors
* Colors for grid coordinate values.
* @param labelColor
* Color for labels if filling.
* @param lev_idx
* Index of the level to process.
* @param out_vv
* Output line display coords for basic lines.
* @param out_bb
* Output colors for basic lines.
* @param out_vvL
* Output line display coords for labels.
* @param out_bbL
* Output colors for label lines.
* @param out_loc
* Output location coords for labels.
* @param dashed
* Flags indicating which levels to dash.
* @throws VisADException
*/
void getLineColorArraysAtCntrLevel(float[] vx, float[] vy, byte[][] colors,
byte[] labelColor, Object labelFont, boolean labelAlign,
boolean sphericalDisplayCS, int lev_idx, boolean[] dashed)
throws VisADException {
// open strips (must end on grid boundary)
int n_strips = vecArray[lev_idx].size();
for (int kk = 0; kk < n_strips; kk++) {
ContourStrip cs = vecArray[lev_idx].get(kk);
cs.isDashed = dashed[lev_idx];
cs.getLabeledLineColorArray(vx, vy, colors, labelColor, labelFont,
labelAlign, sphericalDisplayCS);
}
// closed strips
n_strips = closedStripArray[lev_idx].size();
for (int kk = 0; kk < n_strips; kk++) {
ContourStrip cs = closedStripArray[lev_idx].get(kk);
cs.isDashed = dashed[lev_idx];
cs.getLabeledLineColorArray(vx, vy, colors, labelColor, labelFont,
labelAlign, sphericalDisplayCS);
}
}
/**
* Called just after the grid walking is complete.
*
* @param vx
* @param vy
* @param colors
* shared colors
* @param labelColor
* RGB label color byte array
* @param out_vv
* output vector verticie array {{ X }, { Y }}
* @param out_bb
* @param out_vvL
* @param out_bbL
* @param out_loc
* @param dashFlags
* @param contourDifficulty
* @throws VisADException
*/
void getLineColorArrays(float[] vx, float[] vy, byte[][] colors,
byte[] labelColor, Object labelFont, boolean labelAlign,
boolean sphericalDisplayCS, boolean[] dashFlags)
throws VisADException {
/* Don't use the tiling logic for now.
makeContourStrips(vx, vy);
*/
// set the line and color arrays for each level
for (int kk = 0; kk < n_levs; kk++) {
getLineColorArraysAtCntrLevel(vx, vy, colors, labelColor, labelFont,
labelAlign, sphericalDisplayCS, kk, dashFlags);
}
}
/**
*
* @param vx
* @param vy
*/
void makeContourStrips(float[] vx, float[] vy) {
for (int kk = 0; kk < n_levs; kk++) {
int nx = qSet[kk].nx;
int ny = qSet[kk].ny;
for (int j = 0; j < ny; j++) {
for (int i = 0; i < nx; i++) {
if (qSet[kk].qarray[j][i] == null)
continue;
int[] vert_indices = qSet[kk].qarray[j][i].vert_indices;
int len = qSet[kk].qarray[j][i].numv;
for (int q = 0; q < len; q++) {
int idx = vert_indices[q];
add(vx, vy, idx, idx + 1, kk);
}
}
}
}
}
/**
* Get grid coordinates representing the data at the level specified.
*
* @param lvlIdx
* The level for which to generate an array.
* @return An list of in line strip format, an emtpy list if none.
* @see {@link VisADLineStripArray}
*/
List<float[][][]> getLineStripCoordinates(int lvlIdx) {
if (lvlIdx > vecArray.length - 1) {
return new ArrayList<float[][][]>(0);
}
List<ContourStrip> strips = vecArray[lvlIdx];
List<float[][][]> stripValues = new ArrayList<float[][][]>();
for (ContourStrip strip : strips) {
stripValues.add(strip.getLineStripArrays(gridX, gridY));
}
return stripValues;
}
/**
* Get colors corresponding to the grid coordinates for a level.
*
* @param lvlIdx
* The level for which to get colors.
* @return A list of arrays for the strips that make up the level, an empty
* list if none.
*/
List<byte[][][]> getLineStripColors(int lvlIdx) {
if (lvlIdx > vecArray.length - 1) {
return new ArrayList<byte[][][]>(0);
}
List<ContourStrip> strips = vecArray[lvlIdx];
List<byte[][][]> stripColors = new ArrayList<byte[][][]>();
for (ContourStrip strip : strips) {
;
stripColors.add(strip.getColorStripArrays(gridColors));
}
return stripColors;
}
/**
* Are we using line style for a level.
*
* @param lvl
* The index of the the level.
* @return True if the first strip is using line style, false otherwise.
* There is an assumption that if the first level is styled they all
* are.
*/
boolean isLevelStyled(int lvl) {
if (vecArray.length > lvl + 1 && vecArray[lvl] != null) {
if (vecArray[lvl].size() > 0) {
return vecArray[lvl].get(0).isDashed;
}
}
return false;
}
boolean isLabeled(int lvl) {
return vecArray[lvl].get(0).isLabeled();
}
} //-------- ContourStripSet -------------------
/**
* ContourStrip is used internally by Contour2D to track the indexes associated
* with a strip. Indexes are in line strip format and not line array format.
*/
class ContourStrip {
/** Default label Font */
private static final HersheyFont TIMESR_FONT = new HersheyFont("timesr");
/** Minimum number of points for which to perform label algm */
static final int LBL_ALGM_THRESHHOLD = 20;
/**
* Array of indexes to values in the grid coordinate arrays that make up
* this strip.
*/
IndexPairList idxs = new IndexPairList();
/** Index to the level for this strip in the intervals array. */
int lev_idx;
private boolean isLabeled = false;
/** First index which starts the break for the label. */
private int start_break;
/** Last index which ends the break for the label. */
private int stop_break;
/** Number of indexes that make up the break for the label. */
private int n_skip;
/** Number of labels on this strip. */
int numLabels;
/** Label every Nth line */
int numSkipLines;
boolean isDashed = false;
/** */
PlotDigits plot;
/** */
ContourStripSet css;
boolean closed = false;
/**
*
* @param lev_idx
* @param idx0
* @param idx1
* @param plot
* @param css
*/
ContourStrip(int lev_idx, int idx0, int idx1,
ContourStripSet css) {
this.lev_idx = lev_idx;
idxs.addFirst(idx0, idx1);
this.css = css;
numLabels = css.labelFreq;
numSkipLines = css.labelLineSkip;
}
/**
*
* @param vx
* @param vy
* @param idx0
* @param idx1
*
* @return
*/
boolean addPair(float[] vx, float[] vy, int idx0, int idx1) {
// test for closed strip, bail out early if found
if (closed) return false;
float delta = 0.001f;
float vx0 = vx[idx0];
float vy0 = vy[idx0];
float vx1 = vx[idx1];
float vy1 = vy[idx1];
float vx_s = vx[idxs.first.idx0];
float vy_s = vy[idxs.first.idx0];
float delx = vx0 - vx_s;
float dely = vy0 - vy_s;
if ((delx > -delta && delx < delta) && (dely > -delta && dely < delta)) {
idxs.addFirst(idx1, idx0);
setIsClosed(vx, vy);
return true;
}
delx = vx1 - vx_s;
dely = vy1 - vy_s;
if ((delx > -delta && delx < delta) && (dely > -delta && dely < delta)) {
idxs.addFirst(idx0, idx1);
setIsClosed(vx, vy);
return true;
}
vx_s = vx[idxs.last.idx1];
vy_s = vy[idxs.last.idx1];
delx = vx0 - vx_s;
dely = vy0 - vy_s;
if ((delx > -delta && delx < delta) && (dely > -delta && dely < delta)) {
idxs.addLast(idx0, idx1);
setIsClosed(vx, vy);
return true;
}
delx = vx1 - vx_s;
dely = vy1 - vy_s;
if ((delx > -delta && delx < delta) && (dely > -delta && dely < delta)) {
idxs.addLast(idx1, idx0);
setIsClosed(vx, vy);
return true;
}
return false;
}
/** Check if endpoints are equal and set the closed flag.
*/
void setIsClosed(float[] vx, float[] vy) {
float delta = 0.001f;
float delx = vx[idxs.first.idx0] - vx[idxs.last.idx1];
float dely = vy[idxs.first.idx0] - vy[idxs.last.idx1];
closed = ((idxs.numIndices > 2) && (delx > -delta && delx < delta) && (dely > -delta && dely < delta));
}
/**
*
* @param vx
* @param vy
* @param colors
* @param labelColor
* @param out_vv
* @param out_colors
* @param out_vvL
* @param out_colorsL
* @param lbl_loc
* @throws VisADException
*/
void getLabeledLineColorArray(float[] vx, float[] vy, byte[][] colors,
byte[] labelColor, Object labelFont, boolean labelAlign,
boolean sphericalDisplayCS) throws VisADException {
boolean hasColors = (colors != null);
int linArrLen = idxs.getNumIndices();
// break up each line into chunks according to label frequency
// Below heuristic can be tweaked if desired. Just provides a
// label freq 1 to 9 mapping to point count for repeating the label
int labelRepeat = linArrLen;
switch (numLabels) {
case 1:
labelRepeat = linArrLen;
break;
case 3:
labelRepeat = 200;
break;
case 5:
labelRepeat = 150;
break;
case 7:
labelRepeat = 100;
break;
case 9:
labelRepeat = 50;
break;
default:
labelRepeat = linArrLen;
break;
}
int labelCount = linArrLen / labelRepeat;
int labelRemain = linArrLen % labelRepeat;
if (labelRemain <= 4 && labelRemain > 0 && labelCount > 0) {
labelCount -= 1;
labelRemain += labelRepeat;
}
int labelsDone = 0;
for (int i = 0; i < labelCount; i++) {
int start = i*labelRepeat/2;
int stop = start + labelRepeat/2 - 1;
float[][] vvTmp = getLineArray(vx, vy, start, stop);
byte[][] bbTmp = null;
if (hasColors) {
bbTmp = getColorArray(colors, start, stop);
}
processLineArrays(vvTmp, bbTmp, labelColor, labelFont, labelAlign,
sphericalDisplayCS);
labelsDone++;
}
if (labelRemain > 0) {
int start = labelsDone*labelRepeat/2;
int stop = start + labelRemain/2 - 1;
float[][] vvTmp = getLineArray(vx, vy, start, stop);
byte[][] bbTmp = null;
if (hasColors) {
bbTmp = getColorArray(colors, start, stop);
}
processLineArrays(vvTmp, bbTmp, labelColor, labelFont, labelAlign,
sphericalDisplayCS);
}
}
/**
* Common line array code
*
* @param vv_grid grid coordinates..
*
* @param bb grid color values.
*
* @param labelColor RGB label color byte array
*
* @param out_vv
*
* @param out_colors
*
* @param out_vvL
*
* @param out_colorsL
*
* @param lbl_loc
*/
private void processLineArrays(float[][] vv_grid, byte[][] bb,
byte[] labelColor, Object labelFont, boolean labelAlign,
boolean sphericalDisplayCS) throws VisADException {
float[][] vv = css.spatial_set.gridToValue(vv_grid);
int clr_dim = 0;
if (bb != null)
clr_dim = bb.length;
int totalPts = vv[0].length / 2;
int loc = 0;
int pos = 0;
VisADGeometryArray label = null;
DecimalFormat numFormat = new DecimalFormat();
numFormat.setMaximumFractionDigits(1);
numFormat.setGroupingUsed(false);
String numStr = numFormat.format((double) css.levels[lev_idx]);
float lbl_half = 0.1f;
isLabeled = false;
boolean labelThisLine = false;
// label every Nth line, user can adjust this
if ((lev_idx % css.labelLineSkip) == 0) {
labelThisLine = true;
}
if ((totalPts > LBL_ALGM_THRESHHOLD) && (labelThisLine)) {
isLabeled = true;
loc = (vv[0].length) / 2; // - start at half-way pt.
int n_pairs_b = 1;
int n_pairs_f = 1;
boolean found = false;
float ctr_dist;
pos = loc;
// - get a unit vector parallel to the contour line at the label
// - position.
float del_x;
float del_y;
float del_z;
del_z = vv[2][pos + 1] - vv[2][pos - 1];
del_y = vv[1][pos + 1] - vv[1][pos - 1];
del_x = vv[0][pos + 1] - vv[0][pos - 1];
float mag = (float) Math.sqrt(del_y * del_y + del_x * del_x + del_z
* del_z);
float[] ctr_u = new float[] { del_x / mag, del_y / mag, del_z / mag };
if (ctr_u[0] < 0) {
ctr_u[0] = -ctr_u[0];
ctr_u[1] = -ctr_u[1];
ctr_u[2] = -ctr_u[2];
}
float ctr_u_dot_lbl = ctr_u[0] * 1f + ctr_u[1] * 0f + ctr_u[2] * 0f;
if (labelFont instanceof Font) {
label = PlotText.render_font(numStr, (Font) labelFont,
new double[] { vv[0][loc], vv[1][loc], vv[2][loc] },
new double[] { 1.0, 0.0, 0.0 }, new double[] { 0.0,
1.0, 0.0 }, TextControl.Justification.CENTER,
TextControl.Justification.CENTER, 0.0, css.labelScale,
null);
} else if (labelFont instanceof HersheyFont) {
label = PlotText.render_font(numStr, (HersheyFont) labelFont,
new double[] { vv[0][loc], vv[1][loc], vv[2][loc] },
new double[] { 1.0, 0.0, 0.0 }, new double[] { 0.0,
1.0, 0.0 }, TextControl.Justification.CENTER,
TextControl.Justification.CENTER, 0.0, css.labelScale,
null);
} else if (labelFont == null) {
label = PlotText.render_font(numStr, TIMESR_FONT,
new double[] { vv[0][loc], vv[1][loc], vv[2][loc] },
new double[] { 1.0, 0.0, 0.0 }, new double[] { 0.0,
1.0, 0.0 }, TextControl.Justification.CENTER,
TextControl.Justification.CENTER, 0.0, css.labelScale,
null);
} else {
label = PlotText.render_font(numStr, TIMESR_FONT,
new double[] { vv[0][loc], vv[1][loc], vv[2][loc] },
new double[] { 1.0, 0.0, 0.0 }, new double[] { 0.0,
1.0, 0.0 }, TextControl.Justification.CENTER,
TextControl.Justification.CENTER, 0.0, css.labelScale,
null);
}
float x_min = Float.MAX_VALUE;
float x_max = -Float.MAX_VALUE;
float y_min = Float.MAX_VALUE;
float y_max = -Float.MAX_VALUE;
float z_min = Float.MAX_VALUE;
float z_max = -Float.MAX_VALUE;
for (int k = 0; k < label.vertexCount; k++) {
int i = 3 * k;
float x = label.coordinates[i];
float y = label.coordinates[i + 1];
float z = label.coordinates[i + 2];
if (x > x_max)
x_max = x;
if (y > y_max)
y_max = y;
if (z > z_max)
z_max = z;
if (x < x_min)
x_min = x;
if (y < y_min)
y_min = y;
if (z < z_min)
z_min = z;
}
if (labelAlign) {
lbl_half = (x_max - x_min) / 2;
} else {
if (ctr_u_dot_lbl > 0.5) {
lbl_half = (x_max - x_min) / 2;
} else {
lbl_half = (y_max - y_min);
}
}
lbl_half += lbl_half * 0.08;
// - compute distance between label location (loc) and points
// - on each side, when greater than lbl_half - stop. This
// - assumes that around the label the contour line is fairly
// - linear, seems good approx almost all of time.
while (!found) { // - go backwards, ie decreasing index val
pos -= 2;
if (pos < 0 || pos > (vv[0].length - 1))
return;
float dx = vv[0][pos] - vv[0][loc];
float dy = vv[1][pos] - vv[1][loc];
float dz = vv[2][pos] - vv[2][loc];
ctr_dist = (float) Math.sqrt((double) (dx * dx + dy * dy + dz
* dz));
if (ctr_dist > (float) Math.abs((double) lbl_half)) {
found = true;
} else {
n_pairs_b++;
}
}
pos = loc;
found = false;
while (!found) { // - go fowards, ie increasing index val
pos += 2;
if (pos < 0 || pos > (vv[0].length - 1))
return;
float dx = vv[0][pos] - vv[0][loc];
float dy = vv[1][pos] - vv[1][loc];
float dz = vv[2][pos] - vv[2][loc];
ctr_dist = (float) Math.sqrt((double) (dx * dx + dy * dy + dz
* dz));
if (ctr_dist > (float) Math.abs((double) lbl_half)) {
found = true;
} else {
n_pairs_f++;
}
}
// - total number of points skipped (removed)
n_skip = (n_pairs_b + n_pairs_f) * 2;
// always start_break on even (1st in pair), stop_break on odd index
// (2nd in pair)
if ((loc & 1) == 1) { // - odd
start_break = loc - (1 + (n_pairs_b - 1) * 2);
stop_break = loc + (2 + (n_pairs_f - 1) * 2);
} else { // -even
start_break = loc - (2 + (n_pairs_b - 1) * 2);
stop_break = loc + (1 + (n_pairs_f - 1) * 2);
}
}
boolean doLabel = false;
// - check if label blocks out too may points
if (start_break >= 4 && stop_break <= totalPts * 2 - 3)
doLabel = true;
if (doLabel && isLabeled) {
/*-------LABEL START --------------------*/
float[] ctr_u = null;
float[] norm_x_ctr = null;
// - get a unit vector perpendicular to display coordinate grid
// - at this label location (loc)
float[][] norm = null;
Gridded3DSet cg3d = (Gridded3DSet) css.spatial_set;
norm = cg3d.getNormals(new float[][] { { vv_grid[0][loc] },
{ vv_grid[1][loc] } });
/*
* test if (norm[2][0] < 0) { norm[0][0] = -norm[0][0]; norm[1][0] =
* -norm[1][0]; norm[2][0] = -norm[2][0]; }
*/
float[] labelBase = null;
float[] labelUp = null;
if (labelAlign) { // - align labels with contours
// - get a unit vector parallel to the contour line at the label
// - position.
float del_x;
float del_y;
float del_z;
del_z = vv[2][stop_break] - vv[2][start_break];
del_y = vv[1][stop_break] - vv[1][start_break];
del_x = vv[0][stop_break] - vv[0][start_break];
float mag = (float) Math.sqrt(del_y * del_y + del_x * del_x
+ del_z * del_z);
ctr_u = new float[] { del_x / mag, del_y / mag, del_z / mag };
if (ctr_u[0] < 0) {
ctr_u[0] = -ctr_u[0];
ctr_u[1] = -ctr_u[1];
ctr_u[2] = -ctr_u[2];
}
if (sphericalDisplayCS) {
float[] newNorm = SphericalCoordinateSystem
.getNormal(new float[] { vv[0][pos], vv[1][pos],
vv[2][pos] });
norm[0][0] = newNorm[0];
norm[1][0] = newNorm[1];
norm[2][0] = newNorm[2];
float[] unitI = SphericalCoordinateSystem
.getUnitI(new float[] { vv[0][pos], vv[1][pos],
vv[2][pos] });
float ctr_u_dot_unitI = ctr_u[0] * unitI[0] + ctr_u[1]
* unitI[1] + ctr_u[2] * unitI[2];
if (ctr_u_dot_unitI < 0) {
ctr_u[0] = -ctr_u[0];
ctr_u[1] = -ctr_u[1];
ctr_u[2] = -ctr_u[2];
}
}
// - get a vector perpendicular to contour line, and in the
// local
// - tangent plane. norm_x_ctr: cross-product of local norm and
// - unit vector parallel to contour line at label location.
norm_x_ctr = new float[] {
norm[1][0] * ctr_u[2] - norm[2][0] * ctr_u[1],
-(norm[0][0] * ctr_u[2] - norm[2][0] * ctr_u[0]),
norm[0][0] * ctr_u[1] - norm[1][0] * ctr_u[0] };
mag = (float) Math.sqrt(norm_x_ctr[0] * norm_x_ctr[0]
+ norm_x_ctr[1] * norm_x_ctr[1] + norm_x_ctr[2]
* norm_x_ctr[2]);
// - normalize vector
norm_x_ctr[0] = norm_x_ctr[0] / mag;
norm_x_ctr[1] = norm_x_ctr[1] / mag;
norm_x_ctr[2] = norm_x_ctr[2] / mag;
if (!sphericalDisplayCS) {
if (Math.abs((double) norm[2][0]) <= 0.00001) {
if (norm_x_ctr[2] < 0) {
norm_x_ctr[0] = -norm_x_ctr[0];
norm_x_ctr[1] = -norm_x_ctr[1];
norm_x_ctr[2] = -norm_x_ctr[2];
}
} else {
if (norm_x_ctr[1] < 0) {
norm_x_ctr[0] = -norm_x_ctr[0];
norm_x_ctr[1] = -norm_x_ctr[1];
norm_x_ctr[2] = -norm_x_ctr[2];
}
}
}
labelBase = ctr_u;
labelUp = norm_x_ctr;
} else {
float a = norm[0][0];
float b = norm[1][0];
float c = norm[2][0];
float[] unitI = null;
if (sphericalDisplayCS) {
float[] newNorm = SphericalCoordinateSystem
.getNormal(new float[] { vv[0][pos], vv[1][pos],
vv[2][pos] });
unitI = SphericalCoordinateSystem.getUnitI(new float[] {
vv[0][pos], vv[1][pos], vv[2][pos] });
a = newNorm[0];
b = newNorm[1];
c = newNorm[2];
}
if (visad.util.Util.isApproximatelyEqual(a, 0)
&& visad.util.Util.isApproximatelyEqual(b, 0)) {
labelBase = new float[] { 1, 0, 0 };
labelUp = new float[] { 0, 1, 0 };
} else {
float D = -(a * vv[0][loc] + b * vv[1][loc] + c
* vv[2][loc]);
float K = -D - c * vv[2][loc];
float xLine = vv[0][loc] + 0.5f;
float yLine = (K - a * xLine) / b;
float delX = xLine - vv[0][loc];
float delY = yLine - vv[1][loc];
float mag = (float) Math.sqrt(delX * delX + delY * delY);
float[] uLine = null;
if (sphericalDisplayCS) {
uLine = new float[] { unitI[0], unitI[1], unitI[2] };
} else {
uLine = new float[] { delX / mag, delY / mag, 0 };
}
float[] norm_x_uLine = new float[] {
(b * uLine[2] - c * uLine[1]),
-(a * uLine[2] - c * uLine[0]),
(a * uLine[1] - b * uLine[0]) };
if (norm_x_uLine[2] < 0) {
norm_x_uLine[2] = 1f;
norm_x_uLine[1] = -norm_x_uLine[1];
norm_x_uLine[0] = -norm_x_uLine[0];
}
labelBase = uLine;
labelUp = norm_x_uLine;
}
}
// -- translate to label plot location --------------
if (labelFont instanceof Font) {
label = PlotText
.render_font(numStr, (Font) labelFont, new double[] {
vv[0][loc], vv[1][loc], vv[2][loc] },
new double[] { labelBase[0], labelBase[1],
labelBase[2] }, new double[] {
labelUp[0], labelUp[1], labelUp[2] },
TextControl.Justification.CENTER,
TextControl.Justification.CENTER, 0.0,
css.labelScale, null);
} else if (labelFont instanceof HersheyFont) {
label = PlotText
.render_font(numStr, (HersheyFont) labelFont,
new double[] { vv[0][loc], vv[1][loc],
vv[2][loc] }, new double[] {
labelBase[0], labelBase[1],
labelBase[2] }, new double[] {
labelUp[0], labelUp[1], labelUp[2] },
TextControl.Justification.CENTER,
TextControl.Justification.CENTER, 0.0,
css.labelScale, null);
} else if (labelFont == null) {
label = PlotText
.render_font(numStr, TIMESR_FONT,
new double[] { vv[0][loc], vv[1][loc],
vv[2][loc] }, new double[] {
labelBase[0], labelBase[1],
labelBase[2] }, new double[] {
labelUp[0], labelUp[1], labelUp[2] },
TextControl.Justification.CENTER,
TextControl.Justification.CENTER, 0.0,
css.labelScale, null);
} else {
label = PlotText
.render_font(numStr, TIMESR_FONT,
new double[] { vv[0][loc], vv[1][loc],
vv[2][loc] }, new double[] {
labelBase[0], labelBase[1],
labelBase[2] }, new double[] {
labelUp[0], labelUp[1], labelUp[2] },
TextControl.Justification.CENTER,
TextControl.Justification.CENTER, 0.0,
css.labelScale, null);
}
// no lighting/shading for labels
label.normals = null;
// set the color arrays for label, can be null
byte[] lblClr = null;
if (labelColor != null) {
int clrDim = labelColor.length;
lblClr = new byte[clrDim * label.vertexCount];
for (int kk = 0; kk < label.vertexCount; kk++) {
lblClr[kk * clrDim] = labelColor[0];
lblClr[kk * clrDim + 1] = labelColor[1];
lblClr[kk * clrDim + 2] = labelColor[2];
if (clrDim == 4)
lblClr[kk * clrDim + 3] = labelColor[3];
}
} else if (bb != null) {
lblClr = new byte[clr_dim * label.vertexCount];
for (int kk = 0; kk < label.vertexCount; kk++) {
lblClr[kk * clr_dim] = bb[0][loc];
lblClr[kk * clr_dim + 1] = bb[1][loc];
lblClr[kk * clr_dim + 2] = bb[2][loc];
if (clr_dim == 4)
lblClr[kk * clr_dim + 3] = bb[3][loc];
}
}
label.colors = lblClr;
VisADLineArray labelAnchor = new VisADLineArray();
SampledSet.setGeometryArray(labelAnchor, new float[][] {
{ vv[0][loc] }, { vv[1][loc] }, { vv[2][loc] } }, clr_dim,
null);
/*-------- LABEL DONE -------------------*/
// - this sections creates the contour gap for the label
int s_pos = 0;
int d_pos = 0;
int cnt = start_break;
// - make indexed
float[] lineCoords = new float[3 * ((start_break / 2 + 1)
+ (((totalPts * 2 - start_break) - n_skip) / 2) + 1)];
byte[] lineColors = new byte[clr_dim
* ((start_break / 2 + 1)
+ (((totalPts * 2 - start_break) - n_skip) / 2) + 1)];
float[] fillLineCoords = new float[3 * (n_skip / 2 + 1)];
byte[] fillLineColors = new byte[clr_dim * (n_skip / 2 + 1)];
int lineClrCnt = 0;
int lineCnt = 0;
lineCoords[lineCnt++] = vv[0][0];
lineCoords[lineCnt++] = vv[1][0];
lineCoords[lineCnt++] = vv[2][0];
for (int cc = 0; cc < clr_dim; cc++) {
lineColors[lineClrCnt++] = bb[cc][0];
}
for (int t = 1; t < cnt; t += 2) {
lineCoords[lineCnt++] = vv[0][t];
lineCoords[lineCnt++] = vv[1][t];
lineCoords[lineCnt++] = vv[2][t];
for (int c = 0; c < clr_dim; c++) {
lineColors[lineClrCnt++] = bb[c][t];
}
}
// label fill line
s_pos = start_break;
d_pos = 0;
cnt = n_skip;
fillLineCoords[0] = vv[0][s_pos];
fillLineCoords[1] = vv[1][s_pos];
fillLineCoords[2] = vv[2][s_pos];
for (int cc = 0; cc < clr_dim; cc++) {
fillLineColors[cc] = bb[cc][s_pos];
}
int kk = 3;
int nn = clr_dim;
for (int t = 1; t < n_skip; t += 2) {
fillLineCoords[kk++] = vv[0][s_pos + t];
fillLineCoords[kk++] = vv[1][s_pos + t];
fillLineCoords[kk++] = vv[2][s_pos + t];
for (int cc = 0; cc < clr_dim; cc++) {
fillLineColors[nn++] = bb[cc][s_pos + t];
}
}
VisADLineStripArray fillLineArray = new VisADLineStripArray();
fillLineArray.stripVertexCounts = new int[] { (n_skip / 2) + 1 };
fillLineArray.vertexCount = (n_skip / 2) + 1;
fillLineArray.coordinates = fillLineCoords;
if (fillLineColors.length > 0)
fillLineArray.colors = fillLineColors;
if (isDashed) {
css.fillLinesStyled.add(fillLineArray);
} else {
css.fillLines.add(fillLineArray);
}
// -- end label fill line;
s_pos = stop_break + 1;
d_pos = start_break;
cnt = vv[0].length - s_pos;
// - make indexed
lineCoords[lineCnt++] = vv[0][s_pos];
lineCoords[lineCnt++] = vv[1][s_pos];
lineCoords[lineCnt++] = vv[2][s_pos];
for (int cc = 0; cc < clr_dim; cc++) {
lineColors[lineClrCnt++] = bb[cc][s_pos];
}
for (int t = 1; t < ((totalPts * 2 - start_break) - n_skip); t += 2) {
lineCoords[lineCnt++] = vv[0][s_pos + t];
lineCoords[lineCnt++] = vv[1][s_pos + t];
lineCoords[lineCnt++] = vv[2][s_pos + t];
for (int c = 0; c < clr_dim; c++) {
lineColors[lineClrCnt++] = bb[c][s_pos + t];
}
}
VisADLineStripArray lineArray = new VisADLineStripArray();
lineArray.stripVertexCounts = new int[] { (start_break / 2) + 1,
(((totalPts * 2 - start_break) - n_skip) / 2) + 1 };
lineArray.vertexCount = lineArray.stripVertexCounts[0]
+ lineArray.stripVertexCounts[1];
lineArray.coordinates = lineCoords;
if (lineColors.length > 0) {
lineArray.colors = lineColors;
}
if (isDashed) {
css.cntrLinesStyled.add(lineArray);
} else {
css.cntrLines.add(lineArray);
}
// --- end label gap code
// --- expanding/contracting left-right segments
// - left
s_pos = start_break;
d_pos = 0;
cnt = 2;
// - unit left
float dx = vv[0][loc] - vv[0][s_pos];
float dy = vv[1][loc] - vv[1][s_pos];
float dz = vv[2][loc] - vv[2][s_pos];
float dd = (float) Math
.sqrt((double) (dx * dx + dy * dy + dz * dz));
dx = dx / dd;
dy = dy / dd;
dz = dz / dd;
float mm = dd - (float) Math.abs((double) lbl_half);
dx *= mm;
dy *= mm;
dz *= mm;
byte[][] segColors = new byte[clr_dim][2];
if (bb != null) {
for (int cc = 0; cc < clr_dim; cc++) {
System.arraycopy(bb[cc], s_pos, segColors[cc], d_pos, cnt);
}
}
VisADLineArray expSegLeft = new VisADLineArray();
VisADLineArray segLeftAnchor = new VisADLineArray();
SampledSet.setGeometryArray(expSegLeft, new float[][] {
{ vv[0][s_pos], vv[0][s_pos] + dx },
{ vv[1][s_pos], vv[1][s_pos] + dy },
{ vv[2][s_pos], vv[2][s_pos] + dz } }, clr_dim, segColors);
SampledSet.setGeometryArray(segLeftAnchor, new float[][] {
{ vv[0][s_pos] }, { vv[1][s_pos] }, { vv[2][s_pos] } },
clr_dim, null);
float[] segLeftScaleInfo = new float[] { lbl_half, dd };
// - right
s_pos = stop_break - 1;
d_pos = 0;
cnt = 2;
// - unit right
dx = vv[0][loc] - vv[0][stop_break];
dy = vv[1][loc] - vv[1][stop_break];
dz = vv[2][loc] - vv[2][stop_break];
dd = (float) Math.sqrt((double) (dx * dx + dy * dy + dz * dz));
dx = dx / dd;
dy = dy / dd;
dz = dz / dd;
mm = dd - (float) Math.abs((double) lbl_half);
dx *= mm;
dy *= mm;
dz *= mm;
segColors = new byte[clr_dim][2];
if (bb != null) {
for (int cc = 0; cc < clr_dim; cc++) {
System.arraycopy(bb[cc], s_pos, segColors[cc], d_pos, cnt);
}
}
VisADLineArray expSegRight = new VisADLineArray();
SampledSet.setGeometryArray(expSegRight, new float[][] {
{ vv[0][stop_break], vv[0][stop_break] + dx },
{ vv[1][stop_break], vv[1][stop_break] + dy },
{ vv[2][stop_break], vv[2][stop_break] + dz } }, clr_dim,
segColors);
VisADLineArray segRightAnchor = new VisADLineArray();
SampledSet.setGeometryArray(segRightAnchor, new float[][] {
{ vv[0][stop_break] }, { vv[1][stop_break] },
{ vv[2][stop_break] } }, clr_dim, null);
float[] segRightScaleInfo = new float[] { lbl_half, dd };
// ----- end expanding/contracting line segments
ContourLabelGeometry ctrLabel = new ContourLabelGeometry(label,
labelAnchor, expSegLeft, segLeftAnchor, segLeftScaleInfo,
expSegRight, segRightAnchor, segRightScaleInfo);
ctrLabel.isStyled = isDashed;
css.labels.add(ctrLabel);
} else { // no label
float[] lineCoords = new float[3 * (totalPts + 1)];
byte[] lineColors = new byte[clr_dim * (totalPts + 1)];
int lineClrCnt = 0;
int lineCnt = 0;
lineCoords[lineCnt++] = vv[0][0];
lineCoords[lineCnt++] = vv[1][0];
lineCoords[lineCnt++] = vv[2][0];
for (int cc = 0; cc < clr_dim; cc++) {
lineColors[lineClrCnt++] = bb[cc][0];
}
for (int t = 1; t < totalPts * 2; t += 2) {
lineCoords[lineCnt++] = vv[0][t];
lineCoords[lineCnt++] = vv[1][t];
lineCoords[lineCnt++] = vv[2][t];
for (int c = 0; c < clr_dim; c++) {
lineColors[lineClrCnt++] = bb[c][t];
}
}
VisADLineStripArray lineArray = new VisADLineStripArray();
lineArray.stripVertexCounts = new int[] { (totalPts) + 1 };
lineArray.vertexCount = lineArray.stripVertexCounts[0];
lineArray.coordinates = lineCoords;
if (lineColors.length > 0) {
lineArray.colors = lineColors;
}
if (totalPts >= 2) {
if (isDashed) {
css.cntrLinesStyled.add(lineArray);
} else {
css.cntrLines.add(lineArray);
}
}
}
}
/**
* Get a line array using this instances cached indexes.
*
* @param vx
* X values to apply cached indexes to.
* @param vy
* Y values to apply cached indexes to.
* @see {@link VisADLineArray}
* @return
*/
float[][] getLineArray(float[] vx, float[] vy) {
if (vx == null || vy == null) {
return null;
}
int[] idx_array = idxs.toArray();
float[] vvx = new float[idx_array.length];
float[] vvy = new float[vvx.length];
for (int ii = 0; ii < idx_array.length; ii++) {
vvx[ii] = vx[idx_array[ii]];
vvy[ii] = vy[idx_array[ii]];
}
return new float[][] { vvx, vvy };
}
/**
* Get a line array using this instances cached indexes from start to stop (0-based, inclusive).
*
* @param vx
* X values to apply cached indexes to.
* @param vy
* Y values to apply cached indexes to.
* @param start
* start pair index.
* @param stop
* stop pair index.
* @see {@link VisADLineArray}
*
* @return
*/
float[][] getLineArray(float[] vx, float[] vy, int start, int stop) {
if (vx == null || vy == null) {
return null;
}
int[] idx_array = idxs.toArray(start, stop);
float[] vvx = new float[idx_array.length];
float[] vvy = new float[vvx.length];
for (int ii = 0; ii < idx_array.length; ii++) {
vvx[ii] = vx[idx_array[ii]];
vvy[ii] = vy[idx_array[ii]];
}
return new float[][] { vvx, vvy };
}
/**
* Get line strip arrays for this strip.
*
* @param vx
* X grid coords to apply cached indexes to.
* @param vy
* Y grid coords to apply cached indexes to.
* @return If this strip is has a label the first dim will be 2 arrays, one
* for before the label and one for after. Otherwise the first
* dimension will be a single array for the entire strip.
*/
float[][][] getLineStripArrays(float[] vx, float[] vy) {
int[] idx_array = idxs.toArray();
int count = idx_array.length;
int lenBefore = start_break / 2 + 1;
int lenAfter = (count - stop_break + 1) / 2;
// if we're labeling and there are enough points before
// and after to make at least 1 line
if (isLabeled && (lenBefore >= 2 && lenAfter >= 2)) {
float[][] vvBefore = new float[2][lenBefore];
// the first point in the array
vvBefore[0][0] = vx[idx_array[0]];
vvBefore[1][0] = vy[idx_array[0]];
// every other point up to the start of the break
int kk = 1;
for (int ii = 1; ii < vvBefore[0].length; kk += 2, ii++) {
vvBefore[0][ii] = vx[idx_array[kk]];
vvBefore[1][ii] = vy[idx_array[kk]];
}
// skip to stop_break
kk += n_skip - 1;
float[][] vvAfter = new float[2][lenAfter];
vvAfter[0][0] = vx[idx_array[kk]];
vvAfter[1][0] = vy[idx_array[kk]];
// every other point to the end
kk++;
for (int ii = 1; ii < vvAfter[0].length; kk += 2, ii++) {
vvAfter[0][ii] = vx[idx_array[kk]];
vvAfter[1][ii] = vy[idx_array[kk]];
}
// return new float[][][]{vvAfter};
return new float[][][] { vvBefore, vvAfter };
}
// no label
float[][] vv = null;
if (count == 2) { // can't have less than 2 verticies
vv = new float[2][count];
} else {
vv = new float[2][count / 2 + 1];
}
vv[0][0] = vx[idx_array[0]];
vv[1][0] = vy[idx_array[0]];
for (int kk = 1, ii = 1; ii < vv[0].length; kk += 2, ii++) {
vv[0][ii] = vx[idx_array[kk]];
vv[1][ii] = vy[idx_array[kk]];
}
return new float[][][] { vv };
}
/**
* Get the array of colors corresponding to cached indexes.
*
* @param colors
* Line array formatted colors where the first dimension is the
* color dimension and the second the color values.
* @see {@link VisADLineArray}
* @return Array of colors in line array format.
*/
byte[][] getColorArray(byte[][] colors) {
if (colors == null)
return null;
int clr_dim = colors.length;
int[] idx_array = idxs.toArray();
byte[][] new_colors = new byte[clr_dim][idx_array.length];
for (int ii = 0; ii < idx_array.length; ii++) {
for (int cc = 0; cc < clr_dim; cc++) {
new_colors[cc][ii] = colors[cc][idx_array[ii]];
}
}
return new_colors;
}
/**
* Get the array of colors corresponding to cached indexes from start pair to stop pair (0-based, inclusive).
*
* @param colors
* Line array formatted colors where the first dimension is the
* color dimension and the second the color values.
* @see {@link VisADLineArray}
* @return Array of colors in line array format.
*/
byte[][] getColorArray(byte[][] colors, int start, int stop) {
if (colors == null)
return null;
int clr_dim = colors.length;
int[] idx_array = idxs.toArray(start, stop);
byte[][] new_colors = new byte[clr_dim][idx_array.length];
for (int ii = 0; ii < idx_array.length; ii++) {
for (int cc = 0; cc < clr_dim; cc++) {
new_colors[cc][ii] = colors[cc][idx_array[ii]];
}
}
return new_colors;
}
/**
* Get the array of colors corresponding to cached indexes.
*
* @param colors
* Line array formatted colors where the first dimension is the
* color dimension and the second the color values.
* @see {@link VisADStripLineArray}
* @return Array of colors in line strip array format.
*/
byte[][][] getColorStripArrays(byte[][] colors) {
int clrDim = colors.length;
int[] idx_array = idxs.toArray();
int count = idx_array.length;
int lenBefore = start_break / 2 + 1;
int lenAfter = (count - stop_break + 1) / 2;
if (isLabeled && (lenBefore >= 2 && lenAfter >= 2)) {
byte[][] colorsBefore = new byte[clrDim][start_break / 2 + 1];
// first point
for (int cc = 0; cc < clrDim; cc++) {
colorsBefore[cc][0] = colors[cc][idx_array[0]];
}
// every other redundant point
int kk = 1;
for (int ii = 1; ii < colorsBefore[0].length; kk += 2, ii++) {
for (int cc = 0; cc < clrDim; cc++) {
colorsBefore[cc][ii] = colors[cc][idx_array[kk]];
}
}
kk += n_skip - 1;
byte[][] colorsAfter = new byte[clrDim][(count - stop_break + 1) / 2];
for (int cc = 0; cc < clrDim; cc++) {
colorsAfter[cc][0] = colors[cc][idx_array[kk]];
}
// every other redundant point
kk++;
for (int ii = 1; ii < colorsAfter[0].length; kk += 2, ii++) {
for (int cc = 0; cc < clrDim; cc++) {
colorsAfter[cc][ii] = colors[cc][idx_array[kk]];
}
}
// return new byte[][][]{colorsAfter};
return new byte[][][] { colorsBefore, colorsAfter };
}
// no label
byte[][] bb = null;
if (count == 2) {
bb = new byte[clrDim][count];
} else {
bb = new byte[clrDim][count / 2 + 1];
}
for (int cc = 0; cc < clrDim; cc++) {
bb[cc][0] = colors[cc][idx_array[0]];
}
for (int ii = 1, kk = 1; kk < idx_array.length; kk += 2, ii++) {
for (int cc = 0; cc < clrDim; cc++) {
bb[cc][ii] = colors[cc][idx_array[kk]];
}
}
return new byte[][][] { bb };
}
boolean isLabeled() {
return isLabeled;
}
/**
*
* @param c_strp
*
* @return
*/
void merge(ContourStrip that) {
if (this.lev_idx != that.lev_idx) {
System.out.println("Contour2D.ContourStrip.merge: !BIG ATTENTION!");
}
int[] thisLo = new int[2];
int[] thisHi = new int[2];
int[] thatLo = new int[2];
int[] thatHi = new int[2];
thisLo[0] = this.idxs.first.idx0;
thisLo[1] = this.idxs.first.idx1;
thisHi[0] = this.idxs.last.idx1;
thisHi[1] = this.idxs.last.idx0;
thatLo[0] = that.idxs.first.idx0;
thatLo[1] = that.idxs.first.idx1;
thatHi[0] = that.idxs.last.idx1;
thatHi[1] = that.idxs.last.idx0;
/*
* THAT THIS H----------------------L L---------------------H
*/
if (((thisLo[0] == thatLo[0]) || (thisLo[0] == thatLo[1]))
|| ((thisLo[1] == thatLo[0]) || (thisLo[1] == thatLo[1]))) {
IndexPairList.Node n = that.idxs.first.next; // skip redundant point
// idxs
while (n != null) {
this.idxs.addFirst(n.idx1, n.idx0);
n = n.next;
}
/*
* THAT THIS L----------------------H L---------------------H
*/
} else if (((thisLo[0] == thatHi[0]) || (thisLo[0] == thatHi[1]))
|| ((thisLo[1] == thatHi[0]) || (thisLo[1] == thatHi[1]))) {
this.idxs.first.prev = that.idxs.last.prev; // skip redundant point
// idxs
this.idxs.first.prev.next = this.idxs.first;
this.idxs.first = that.idxs.first;
this.idxs.numIndices = this.idxs.numIndices + that.idxs.numIndices
- 2;
/*
* THIS THAT L----------------------H H---------------------L
*/
} else if (((thisHi[0] == thatHi[0]) || (thisHi[0] == thatHi[1]))
|| ((thisHi[1] == thatHi[0]) || (thisHi[1] == thatHi[1]))) {
IndexPairList.Node n = that.idxs.last.prev; // skip redundant point
// idxs
while (n != null) {
this.idxs.addLast(n.idx1, n.idx0);
n = n.prev;
}
/*
* THIS THAT L----------------------H L---------------------H
*/
} else if (((thisHi[0] == thatLo[0]) || (thisHi[0] == thatLo[1]))
|| ((thisHi[1] == thatLo[0]) || (thisHi[1] == thatLo[1]))) {
this.idxs.last.next = that.idxs.first.next; // skip redundant point
// idxs
this.idxs.last.next.prev = this.idxs.last;
this.idxs.last = that.idxs.last;
this.idxs.numIndices = this.idxs.numIndices + that.idxs.numIndices
- 2;
}
}
/**
*
* @return
*/
public String toString() {
return "<" + this.getClass().getName() + "(" + idxs.first.idx0 + ","
+ idxs.first.idx1 + "), (" + idxs.last.idx0 + ","
+ idxs.first.idx1 + ")>";
}
} //--------- ContourStrip ------------------/
/**
* A double ended list for pairs of integers implemented as a doubly linked
* list.
*/
class IndexPairList {
/**
* Node object of a pair of indices.
*/
static final class Node {
Node prev;
Node next;
final int idx0;
final int idx1;
Node(int idx0, int idx1) {
this.idx0 = idx0;
this.idx1 = idx1;
}
}
/**
* Total number of indices which will always be the number of nodes divided
* by 2.
*/
int numIndices = 0;
/** Last pair node in list. */
Node last;
/** First pair node in list. */
Node first;
/**
* Create a node for the pair of indices and add to the beginning of this
* list.
*
* @param i0
* @param i1
*/
void addFirst(int i0, int i1) {
addFirst(new Node(i0, i1));
}
/**
* Add a node the the beginning of this list.
*
* @param n
*/
private void addFirst(Node n) {
n.next = null;
n.prev = null;
if (numIndices == 0) {
first = n;
last = n;
} else {
first.prev = n;
n.next = first;
first = n;
}
numIndices += 2;
}
/**
* Create a node for the pair of indices and add to the end of this list.
*
* @param i0
* @param i1
*/
void addLast(int i0, int i1) {
addLast(new Node(i0, i1));
}
/**
* Add the Node to the end of this list.
*
* @param n
*/
private void addLast(Node n) {
n.next = null;
n.prev = null;
if (numIndices == 0) {
last = n;
first = n;
} else {
last.next = n;
n.prev = last;
last = n;
}
numIndices += 2;
}
/**
* Clear the list.
* <p>
* NOTE: We do not need to null out all the node objects because the garbage
* collector is <u>supposed</u> to collect even cyclic references.
*/
void clear() {
first = null;
last = null;
numIndices = 0;
}
int getNumIndices() {
return numIndices;
}
/**
* Return array of this lists indices. Each nodes idx0 precedes it's idx1
* with a total array length of <code>numIndices</code>.
*
* @return
*/
int[] toArray() {
int[] idxs = new int[numIndices];
int idx = 0;
Node n = first;
while (n != null) {
idxs[idx++] = n.idx0;
idxs[idx++] = n.idx1;
n = n.next;
}
return idxs;
}
/**
* Return array of this list's indices from start pair to stop pair index (0-based and inclusive).
*
* @param start index of first pair.
* @param stop index of last pair.
*
* @return array of length num of pairs (inclusive) times two.
*/
int[] toArray(int start, int stop) {
int[] idxs = new int[(stop - start + 1)*2];
int pairIdx = 0;
Node n = first;
int cnt = 0;
while (pairIdx <= stop && n != null) {
if (pairIdx >= start) {
idxs[cnt++] = n.idx0;
idxs[cnt++] = n.idx1;
}
n = n.next;
pairIdx += 1;
}
return idxs;
}
}