Re: Alpha and Java



Bill Hibbard wrote:
Hi Kevin,

Regarding my issues with VisAD/Java/Java3D and possible Alpha
interference using a filled Irregular2DSet (please see bottom of
message) - I think I may have finally isolated the culprit.

It appears that when Blackdown went from their java3D-1.2.1_03 to
java3d-1.3* is when the change in behavior occurs.  With the old version
I got a clean transparent feature.  When I upgraded to the newer java3d,
that same feature gave me the "interference" pattern you see in the
link(s) below.  Unfortunately, every combination of java-1.4.2* and
anything newer than java3D-1.2.1_03 has given me this result.  (On the
plus side, it blends overlapping - but different Z-depth - alpha objects
very well compared to the older version)

I have some relatively simple code (2 apps) which you can use to see the
difference in behavior.  (I'll leave it up to the adventurous to do
their multiple Java* install if they want to test this.)  Let me know
and I'll send the programs.


Yes, please send me the programs to generate this problem.



Please see the attached files. Note, alphaTest2 requires BeamPath (also attached).

Let me know if there are any questions.  Thanks for looking into this!

-kevin.




--
+------------------------------------------------------------+
Kevin L. Manross        [KD5MYD] <><          (405)-366-0557
CIMMS Research Associate               kevin.manross@xxxxxxxx
[NSSL-WRDD/SWATN]           http://www.cimms.ou.edu/~kmanross

"My opinions are my own and not representative of CIMMS, NSSL,
 NOAA or any affiliates"
+------------------------------------------------------------+
/**  AlphaTest1.java displays for triangles partially overlayed by "Z-depth"
 *   and semi-transparent (alpha).  With the older Java3D (Blackdown v1.2.1_03)
 *   there is no "blending" of the overlapping triangles #unless you rotate the
 *   display and view then from the "back side"#  With later versions of
 *   Blackdown's Java3D, the overlap blending appears normal.
 **/


import java.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.IOException;

import java.awt.*;
import java.awt.event.*;

import visad.*;
import java.rmi.RemoteException;
import visad.java3d.*;
import visad.bom.Radar2DCoordinateSystem;
import visad.data.netcdf.Plain;


public class alphaTest1 extends JPanel implements ActionListener
{

  private DisplayImpl display;
  private RealType lat, lon, red, green, blue, alpha, z;
  private RealTupleType latLon_tt, lonLat_tt, latLonAlt_tt;
  private ScalarMap latMap, lonMap, rMap, gMap, bMap, aMap, zMap;
  private DataReferenceImpl dataRef;
  private double[] projMatrix;
  float[] radarLocation;
  private JButton reset = new JButton("Reset");
  float radarLat, radarLon, radarAlt;

  public alphaTest1() throws VisADException, RemoteException, IOException
  {

    radarLocation = new float[]{33.289f, -111.670f, 427.0f};
    radarLat = radarLocation[0];
    radarLon = radarLocation[1];
    radarAlt = radarLocation[2];
    reset.addActionListener(this);

    lat = RealType.Latitude;
    lon = RealType.Longitude;
    red = RealType.getRealType("Red");
    green = RealType.getRealType("Green");
    blue = RealType.getRealType("Blue");
    alpha = RealType.getRealType("Alpha");
    z = RealType.getRealType("z");

    latLon_tt = new RealTupleType(lat, lon);
    lonLat_tt = new RealTupleType(lon, lat);

    latMap = new ScalarMap(RealType.Latitude, Display.YAxis);
    lonMap = new ScalarMap(RealType.Longitude, Display.XAxis);
    rMap = new ScalarMap(red, Display.Red);
    gMap = new ScalarMap(green, Display.Green);
    bMap = new ScalarMap(blue, Display.Blue);
    aMap = new ScalarMap(alpha, Display.Alpha);
    zMap = new ScalarMap(z, Display.ZAxis);

//    display = new DisplayImplJ3D( "TextDisplay", new TwoDDisplayRendererJ3D() 
);
    display = new DisplayImplJ3D( "TextDisplay" );
    display.addMap(latMap);
    display.addMap(lonMap);
    display.addMap(rMap);
    display.addMap(gMap);
    display.addMap(bMap);
    display.addMap(aMap);
    display.addMap(zMap);

    rMap.setRange( 0.0f, 1.0f );
    gMap.setRange( 0.0f, 1.0f );
    bMap.setRange( 0.0f, 1.0f );
    aMap.setRange( 0.0f, 1.0f );
    zMap.setRange( -1.0f, 1.0f );

    DisplayRendererJ3D dr = (DisplayRendererJ3D)display.getDisplayRenderer();
    MouseBehaviorJ3D mb = (MouseBehaviorJ3D)dr.getMouseBehavior();
    ProjectionControl initPC = display.getProjectionControl();
    projMatrix = initPC.getMatrix();
    double scale = 1.4;
    double[] newMatrix = mb.make_matrix(0.0, 0.0, 0.0, scale, 0.0, 0.0, 0.0);
    newMatrix = mb.multiply_matrix(newMatrix, projMatrix);
    initPC.setMatrix(newMatrix);
    projMatrix = initPC.getMatrix();

    GraphicsModeControl gmc = display.getGraphicsModeControl();
    gmc.setScaleEnable(true);
    gmc.setProjectionPolicy(DisplayImplJ3D.PARALLEL_PROJECTION);
//    gmc.setMissingTransparent(false);
//    gmc.setTransparencyMode(DisplayImplJ3D.NICEST);


    lonMap.setRange(-115.975, -107.375);
    latMap.setRange(29.7, 36.883);

    float azimuth = 2.0f;
    float beamWidth = 7.0f;
    float elevAngle = 0.5f;
    // ### meters
    float beginRan = 1000.0f;
    float endRan = 400000.0f;

    Irregular2DSet widthSet0 = (Irregular2DSet) makeBeamFill(azimuth, 
beamWidth, elevAngle, 
                                                                         
beginRan, endRan);

    azimuth = 5.0f;

    Irregular2DSet widthSet1 = (Irregular2DSet) makeBeamFill(azimuth, 
beamWidth, elevAngle, 
                                                                       
beginRan, endRan);

    azimuth = 8.0f;

    Irregular2DSet widthSet2 = (Irregular2DSet) makeBeamFill(azimuth, 
beamWidth, elevAngle, 
                                                                       
beginRan, endRan);

    azimuth = 11.0f;

    Irregular2DSet widthSet3 = (Irregular2DSet) makeBeamFill(azimuth, 
beamWidth, elevAngle, 
                                                                       
beginRan, endRan);

    MathType[] mWidthType = new MathType[] { 
                                             red, green, blue, alpha, z, 
widthSet1.getType()
                                           };

    TupleType widthTupleType = new TupleType(mWidthType);
    Tuple[] widthTuple = new Tuple[4];

    /** Ghange variable values in these Data[] arrays */
    Data[] widthData0 = new Data[] {
                                    new Real(red, 1.00f),
                                    new Real(green, 1.00f),
                                    new Real(blue, 1.00f),
                                    new Real(alpha, 0.5f),
                                    new Real(z, 0.9f),
                                    widthSet0
                                  };
    Data[] widthData1 = new Data[] {
                                    new Real(red, 1.00f),
                                    new Real(green, 0.00f),
                                    new Real(blue, 0.00f),
                                    new Real(alpha, 0.5f),
                                    new Real(z, 0.8f),
                                    widthSet1
                                  };
    Data[] widthData2 = new Data[] {
                                    new Real(red, 0.00f),
                                    new Real(green, 1.00f),
                                    new Real(blue, 0.00f),
                                    new Real(alpha, 0.5f),
                                    new Real(z, 0.7f),
                                    widthSet2
                                  };
    Data[] widthData3 = new Data[] {
                                    new Real(red, 0.00f),
                                    new Real(green, 0.00f),
                                    new Real(blue, 1.00f),
                                    new Real(alpha, 0.5f),
                                    new Real(z, 0.6f),
                                    widthSet3
                                  };

    widthTuple[0] =  new Tuple(widthTupleType, widthData0);
    widthTuple[1] =  new Tuple(widthTupleType, widthData1);
    widthTuple[2] =  new Tuple(widthTupleType, widthData2);
    widthTuple[3] =  new Tuple(widthTupleType, widthData3);

    RealType index = RealType.getRealType("index");
    Integer1DSet indexSet = new Integer1DSet(index, 4);
    FunctionType fType = new FunctionType(index, widthTupleType);
    FieldImpl field = new FieldImpl(fType, indexSet);
    field.setSamples(widthTuple, false);

    DataReferenceImpl widthField = new DataReferenceImpl("widthField");
    display.addReference(widthField);
    widthField.setData(field);

    setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
    setAlignmentY(JPanel.TOP_ALIGNMENT);
    setAlignmentX(JPanel.LEFT_ALIGNMENT);

    Component comp = display.getComponent();
    ((JComponent)comp).setPreferredSize( new Dimension(500,500) );

    add(comp);
    add(reset);
  }

  public Set makeBeamFill(float azimuth, float beamWidth, float elevAngle, 
float beginRan, 
                                              float endRan) throws 
VisADException, RemoteException
  {
    // ## From radar point of view
    float leftAz = (float) (azimuth - 0.5f * beamWidth);
    float rightAz = (float) (azimuth + 0.5f * beamWidth);

    // ### return vals are lat/lon/ht
/*
    double[] leftClose = 
               CoordConversion.AzRangetoLL(radarLat, radarLon, leftAz, 
beginRan, elevAngle);
    double[] leftFar = 
               CoordConversion.AzRangetoLL(radarLat, radarLon, leftAz, endRan, 
elevAngle);
    double[] rightClose = 
               CoordConversion.AzRangetoLL(radarLat, radarLon, rightAz, 
beginRan, elevAngle);
    double[] rightFar = 
               CoordConversion.AzRangetoLL(radarLat, radarLon, rightAz, endRan, 
elevAngle);
*/

    float[] leftClose = 
               coordConversion(leftAz, beginRan);
    float[] leftFar = 
               coordConversion(leftAz, endRan);
    float[] rightClose = 
               coordConversion(rightAz, beginRan);
    float[] rightFar = 
               coordConversion(rightAz, endRan);

/*
    System.out.println("Corners: " + leftClose[0] + ", " + leftFar[0] 
                               + " - " + rightClose[0] + ", " + rightFar[0]);
*/

    float[] latVals = new float[]{ 
        (float)rightFar[0], (float)rightClose[0], (float)leftClose[0], 
(float)leftFar[0]
                                 };
    float[] lonVals = new float[]{ 
        (float)rightFar[1], (float)rightClose[1], (float)leftClose[1], 
(float)leftFar[1]
                                 };

    float[][] corners = new float[][] { latVals, lonVals};

    Gridded2DSet cornersSet = new Gridded2DSet(latLon_tt, corners, 4);
    Irregular2DSet filledWidthSet = DelaunayCustom.fill(cornersSet);
    return filledWidthSet;

  }


  public float[] coordConversion(float az, float ran) throws VisADException, 
RemoteException
  {
    Radar2DCoordinateSystem r = new Radar2DCoordinateSystem(radarLat, radarLon);
    float[][] raVals = new float[][] { {ran}, {az} };
    float[][] llValsTemp = r.toReference(raVals);
    float[] llVals = new float[] {llValsTemp[0][0], llValsTemp[1][0]};
    return llVals;
  }


  public void actionPerformed(ActionEvent e)
  { resetOrientation(); }


  /**
   * Resets the display projection to its original value.
   * Borrowed from VisAD SpreadSheet
   */
  public void resetOrientation() {
    if (display != null) {
      ProjectionControl pc = display.getProjectionControl();
      if (pc != null) {
        try {
          pc.setMatrix(projMatrix);
        }
        catch (VisADException exc) {
          System.out.println("Cannot reset orientation" + exc);
        }
        catch (RemoteException exc) {
          System.out.println("Cannot reset orientation" + exc);
        }
      }
    }
  }


  public static void main(String[] args) throws VisADException, 
RemoteException, IOException
  {
    JFrame frame = new JFrame("AlphaTest");
    alphaTest1 me = new alphaTest1();

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(me);
    frame.pack();
    frame.setVisible(true);
  }


}


/**
  * AlphaTest2 uses "BeamPath.java" to create two radar beampaths and
  * then "fills" between the paths using an Irregular2DSet.  With the 
  * older version of Java3D (Blackdown's 1.2.1_03) the transparent fill
  * is normal.  Using a later version of Blackdown Java3D, the fill
  * shows up as an apparent "interference pattern".
  **/

import java.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.IOException;

import java.awt.*;
import java.awt.event.*;

import visad.*;
import java.rmi.RemoteException;
import visad.java3d.*;
import visad.bom.Radar2DCoordinateSystem;
import visad.data.netcdf.Plain;
import visad.data.units.*;


public class alphaTest2 extends JPanel implements ActionListener
{

  private DisplayImpl display;
  private RealType red, green, blue, alpha, z;
  private ScalarMap rMap, gMap, bMap, aMap, zMap;
  private DataReferenceImpl dataRef;
  private double[] projMatrix;
  float[] radarLocation;
  private JButton reset = new JButton("Reset");
  private Unit kilometer, km;
  BeamPath beamPath;

  public alphaTest2() throws VisADException, RemoteException, IOException
  {
    /** Parameter Setup */
    try
    { kilometer = Parser.parse("kilometer").clone("km"); }
    catch (ParseException P)
    { System.out.println("ParseException: " + P); }
    catch (UnitException U)
    { System.out.println("UnitException: " + U); }

    RealType sRange = RealType.getRealType("SlantRange", kilometer, null);
    RealType range = RealType.getRealType("Range", kilometer, null);
    RealType height = RealType.getRealType("Height", kilometer, null);
    RealTupleType rangeHeightType = new RealTupleType(range, height);
    ScalarMap rangeMap = new ScalarMap(range, Display.XAxis);
    ScalarMap heightMap = new ScalarMap(height, Display.YAxis);

    red = RealType.getRealType("Red");
    green = RealType.getRealType("Green");
    blue = RealType.getRealType("Blue");
    alpha = RealType.getRealType("Alpha");
    z = RealType.getRealType("z");

    rMap = new ScalarMap(red, Display.Red);
    gMap = new ScalarMap(green, Display.Green);
    bMap = new ScalarMap(blue, Display.Blue);
    aMap = new ScalarMap(alpha, Display.Alpha);
    zMap = new ScalarMap(z, Display.ZAxis);



    /** Display Stuff */
//    display = new DisplayImplJ3D( "TextDisplay", new TwoDDisplayRendererJ3D() 
);
    display = new DisplayImplJ3D( "TextDisplay" );

    display.addMap(rMap);
    display.addMap(gMap);
    display.addMap(bMap);
    display.addMap(aMap);
    display.addMap(zMap);
    display.addMap(rangeMap);
    display.addMap(heightMap);

    rMap.setRange( 0.0f, 1.0f );
    gMap.setRange( 0.0f, 1.0f );
    bMap.setRange( 0.0f, 1.0f );
    aMap.setRange( 0.0f, 1.0f );
    zMap.setRange( -1.0f, 1.0f );

    DisplayRendererJ3D dr = (DisplayRendererJ3D)display.getDisplayRenderer();
    MouseBehaviorJ3D mb = (MouseBehaviorJ3D)dr.getMouseBehavior();
    ProjectionControl initPC = display.getProjectionControl();
    projMatrix = initPC.getMatrix();
    double scale = 1.4;
    double[] newMatrix = mb.make_matrix(0.0, 0.0, 0.0, scale, 0.0, 0.0, 0.0);
    newMatrix = mb.multiply_matrix(newMatrix, projMatrix);
    initPC.setMatrix(newMatrix);
    projMatrix = initPC.getMatrix();

    GraphicsModeControl gmc = display.getGraphicsModeControl();
    gmc.setScaleEnable(true);
    gmc.setProjectionPolicy(DisplayImplJ3D.PARALLEL_PROJECTION);




    /** **** BeamPath stuff **** */
    ConstantMap[] beamCMap = { 
                               new ConstantMap(-0.9f, Display.ZAxis),
                               new ConstantMap(0.5f, Display.Alpha) 
                             };

    beamPath = new BeamPath( 451, 400 );
    beamPath.setEnteredBeamWidth("1.0");
    beamPath.elevationUpdate("00.50");
    DataReferenceImpl beamFillRef = new DataReferenceImpl("beamFillRef");
    display.addReference(beamFillRef, beamCMap);
    beamFillRef.setData( beamPath.getBeamFill() );
    /** **** End BeamPath stuff  **** */




    /** Display Layout */
    setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
    setAlignmentY(JPanel.TOP_ALIGNMENT);
    setAlignmentX(JPanel.LEFT_ALIGNMENT);

    Component comp = display.getComponent();
    ((JComponent)comp).setPreferredSize( new Dimension(500,500) );

    add(comp);
    add(reset);
  }


  public void actionPerformed(ActionEvent e)
  { resetOrientation(); }


  /**
   * Resets the display projection to its original value.
   * Borrowed from VisAD SpreadSheet
   */
  public void resetOrientation() {
    if (display != null) {
      ProjectionControl pc = display.getProjectionControl();
      if (pc != null) {
        try {
          pc.setMatrix(projMatrix);
        }
        catch (VisADException exc) {
          System.out.println("Cannot reset orientation" + exc);
        }
        catch (RemoteException exc) {
          System.out.println("Cannot reset orientation" + exc);
        }
      }
    }
  }


  public static void main(String[] args) throws VisADException, 
RemoteException, IOException
  {
    JFrame frame = new JFrame("AlphaTest");
    alphaTest2 me = new alphaTest2();

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(me);
    frame.pack();
    frame.setVisible(true);
  }


}


/**
  * BeamPath calculates the propagation path of a radar beam using equations
  * from Doviak & Zrnic (1993).
  **/


import java.*;
import java.util.Vector;
import visad.*;
import visad.bom.*;
import visad.data.units.*;
import java.rmi.RemoteException;


public class BeamPath
{

  final static double INDEX_OF_REFRACTION = (4.0/3.0);
  final static double EARTH_RADIUS = 6378; // km at Equator
  final static double RADIANS = (Math.PI/180);
  static double MAX_RANGE;
  private RealType sRange, range, height;
  private TextType text;
  private RealTupleType rangeHeightType;
  private String currentVCP;
  private Unit kilometer, km;
  private UnionSet vcpBeamWidthSet, allBeamsFill;
  private Irregular2DSet beamFill;
  private double radarElevation, elevationAngle, enteredBeamWidth;
  private int numberOfElevationAnglesInCurrentVCP;

  private FlatField singlePath;
  private UnionSet singleWidth;
  private Irregular2DSet singleFill;
  private Tuple singleLabel;
//  private Gridded2DSet[] vcpPaths;
  private FlatField[] vcpPaths;
  private UnionSet[] vcpWidths;
  private Irregular2DSet[] vcpFills;
  private Tuple[] vcpLabels;
  

  public BeamPath(double re, double maxRange) throws RemoteException, 
VisADException
  {

    MAX_RANGE = maxRange;  

    try
    { kilometer = Parser.parse("kilometer").clone("km"); }
    catch (ParseException P)
    { System.out.println("ParseException: " + P); }
    catch (UnitException U)
    { System.out.println("UnitException: " + U); }
  
    sRange = RealType.getRealType("SlantRange", kilometer, null);
    range = RealType.getRealType("Range", kilometer, null);
    height = RealType.getRealType("Height", kilometer, null);
    rangeHeightType = new RealTupleType(range, height);
    text = TextType.getTextType("Text");

    radarElevation = re;

  }



  /**
   * Calculate the radar range (and azimuth) between to sets of
   * Lat/Lon coordinates
   */
  public double calcLatLonRange(double lat1, double lon1,
                                                  double lat2, double lon2)
  {
     double term1, term2, term3, inside, distance, rLat1, rLon1, rLat2, rLon2;
     rLat1 = Math.PI*lat1/180;
     rLon1 = Math.PI*lon1/180;
     rLat2 = Math.PI*lat2/180;
     rLon2 = Math.PI*lon2/180;
     term1 = Math.cos(rLat1)*Math.cos(rLon1)*Math.cos(rLat2)*Math.cos(rLon2);
     term2 = Math.cos(rLat1)*Math.sin(rLon1)*Math.cos(rLat2)*Math.sin(rLon2);
     term3 = Math.sin(rLat1)*Math.sin(rLat2);
     inside = term1 + term2 + term3;
     distance = Math.acos(inside)  * EARTH_RADIUS;
     return distance;
  }



  /**
   * Calculate the radar range (and azimuth) between to sets of
   * Lat/Lon coordinates using visad.bom.Radar2DCoordinateSystem
   */
  public float[][] calcLatLonRange(float sLat, float sLon, 
           float eLat, float eLon) throws VisADException, RemoteException
  {
    Radar2DCoordinateSystem radarSystem = 
                                new Radar2DCoordinateSystem(sLat, sLon);

    float[][] distance = radarSystem.fromReference(new float[][] { {eLon}, 
{eLat} } );

    return distance;
  }



  /**
   * Calculate the beampaths for all the elevations for the current VCP
   */

/* 
  public UnionSet vcpBeamPaths()
                          throws VisADException, RemoteException
  {
    return vcpBeamPaths(currentVCP);
  }
*/

  public void vcpUpdate()
                          throws VisADException, RemoteException
  {
     vcpUpdate(currentVCP);
  }

  /**
   * Calculate the beampaths for all the elevations in a given VCP
   */ 

  public void vcpUpdate(String elevations)
                          throws VisADException, RemoteException
  {
    setVCP(elevations);
    String[] indivElevationAngles = elevations.split(",");
    int NUM_ELS = indivElevationAngles.length;
    setNumElevationAngles(NUM_ELS);

    MathType[] mtypes = {range, height, text};
    TupleType text_tuple = new TupleType(mtypes);

    FlatField[] beamPaths = new FlatField[NUM_ELS];
    UnionSet[] beamWidths = new UnionSet[NUM_ELS];
    Irregular2DSet[] beamFills = new Irregular2DSet[NUM_ELS];
    Tuple[] beamLabels = new Tuple[NUM_ELS];

    float[][][] valsTemp = new float[NUM_ELS][][];

    for (int i = 0; i < NUM_ELS; i++)
    {
      double el = Double.parseDouble( indivElevationAngles[i] );
      valsTemp[i] = calcBeamPath(el, MAX_RANGE);

      beamPaths[i] = beamPath(valsTemp[i]);
      beamWidths[i] = plotCurrentBeamWidth( el );
      beamFills[i] = fillBeamWidth( beamWidths[i] );

      Data td[] = {new Real(range, valsTemp[i][0][valsTemp[i][0].length - 1]),
                   new Real(height, valsTemp[i][1][valsTemp[i][1].length - 1]),
                   new Text(text, indivElevationAngles[i] )};
      beamLabels[i] = new Tuple(text_tuple, td);
    }

    setBeamPaths( beamPaths );
    setBeamWidths( beamWidths );
    setBeamFills( beamFills );
    setBeamLabels( beamLabels );

  }


  public void elevationUpdate(String elevation) throws VisADException, 
RemoteException
  {

    double el = Double.parseDouble( elevation );
    float[][] valsTemp = calcBeamPath(el, MAX_RANGE);
    MathType[] mtypes = {range, height, text};
    TupleType text_tuple = new TupleType(mtypes);
    setElevationAngle( el);

    FlatField path = beamPath();
    UnionSet width = plotCurrentBeamWidth( el );
    Irregular2DSet fill = fillBeamWidth(width);
   
    Data td[] = {new Real(range, valsTemp[0][valsTemp[0].length - 1]),
                 new Real(height, valsTemp[1][valsTemp[1].length - 1]),
                 new Text(text, elevation )};
    Tuple label = new Tuple(text_tuple, td);
 
    setBeamPath( path );
    setBeamWidth( width );
    setBeamFill( fill );
    setBeamLabel( label );
  }
    


  /**
   * Calculate the radar beam path relative to a GreatCircle (Earth's surface)
   * and return a FlatField of height(range), Equations are from Doviak and 
Zrnic (1993)
   * p21, equations 2.28b and c
   */
  public float[][] calcBeamPath(double elevAngle, double maxRange) 
                                      throws VisADException, RemoteException
  {
    double MAX_RANGE = maxRange;
    int BEAMPATHSAMPLING = 400;
    double E_ANGLE = elevAngle * RADIANS;
    double EFFECTIVE_EARTH_RADIUS = INDEX_OF_REFRACTION * EARTH_RADIUS;

    Vector ht = new Vector();
    Vector rn = new Vector();

    float[][] heightVals;
    float[][] rangeVals;

    Linear1DSet r_set = new Linear1DSet(0.0, maxRange, BEAMPATHSAMPLING);
    float[][] slantRange = r_set.getSamples(true);
    Irregular1DSet rangeSet;
    FlatField beamPath_ff;
    FunctionType rangeHeightFunc = new FunctionType(range, height);
    
    for (int i = 0; i < BEAMPATHSAMPLING; i++)
    {
      double inside = ((Math.pow(slantRange[0][i],2)) + 
(Math.pow(EFFECTIVE_EARTH_RADIUS,2))
                            + 
(2*slantRange[0][i]*EFFECTIVE_EARTH_RADIUS*Math.sin(E_ANGLE)));
      double outside = EFFECTIVE_EARTH_RADIUS;
      Float n = new Float( (float)( (radarElevation/1000) + 
((Math.pow(inside,0.5)) - outside)) );
      ht.add(n);

      double numer = (slantRange[0][i]*Math.cos(E_ANGLE));
      double denom = (EFFECTIVE_EARTH_RADIUS + n.floatValue() );
      double quo = (numer/denom);
      Float o = new Float( (float)(EFFECTIVE_EARTH_RADIUS*Math.asin(quo)) );
      rn.add(o);

      if (n.floatValue() > 25.0)
      { break; }

      else if (o.floatValue() > MAX_RANGE)
      { break; }

    }

    float[][] rangeAndHeight = new float[2][rn.size()];

    Float[] e = (Float[]) ht.toArray(new Float[ht.size()]);
    Float[] f = (Float[]) rn.toArray(new Float[rn.size()]);
    for (int g = 0; g < ht.size(); g++)
    {
      rangeAndHeight[0][g] = f[g].floatValue();
      rangeAndHeight[1][g] = e[g].floatValue();
    }

    return rangeAndHeight;
  }



  /**
   * Get the calculated BeamPath and make it into a FlatField
   */
  public FlatField beamPath() throws VisADException, RemoteException
  {
    Irregular1DSet rangeSet;
    FlatField beamPath_ff;
    FunctionType rangeHeightFunc = new FunctionType(range, height);

    float[][] rangeThenHeight = calcBeamPath(elevationAngle, MAX_RANGE);
    float[][] rangeVals = new float[1][rangeThenHeight[0].length];
    float[][] heightVals = new float[1][rangeThenHeight[1].length];

    rangeVals[0] = rangeThenHeight[0];
    heightVals[0] = rangeThenHeight[1];

    rangeSet = new Irregular1DSet(range, rangeVals);
    beamPath_ff = new FlatField(rangeHeightFunc, rangeSet);
    beamPath_ff.setSamples(heightVals);

    return beamPath_ff;
  }

    
  
  /**
   * Given a 2D array for a beam path, make it into a FlatField
   */
  public FlatField beamPath(float[][] beamPathVals) throws VisADException, 
RemoteException
  {
    Irregular1DSet rangeSet;
    FlatField beamPath_ff;
    FunctionType rangeHeightFunc = new FunctionType(range, height);

//    float[][] rangeThenHeight = calcBeamPath(elevationAngle, MAX_RANGE);
    float[][] rangeVals = new float[1][beamPathVals[0].length];
    float[][] heightVals = new float[1][beamPathVals[1].length];

    rangeVals[0] = beamPathVals[0];
    heightVals[0] = beamPathVals[1];

    rangeSet = new Irregular1DSet(range, rangeVals);
    beamPath_ff = new FlatField(rangeHeightFunc, rangeSet);
    beamPath_ff.setSamples(heightVals);

    return beamPath_ff;
  }




  /**
   * Plot the top and bottom of the BeamWidth given the curent elevation angle
   */
  public UnionSet plotCurrentBeamWidth() throws VisADException, RemoteException
  {
    return plotCurrentBeamWidth(elevationAngle);
  }



  /**
   * Plot the top and bottom of the BeamWidth given an elevation angle and the 
current beamwidth
   */
  public UnionSet plotCurrentBeamWidth(double elAngle) throws VisADException, 
RemoteException
  {
    float[][] topRangeHeight = calcBeamPath(getBeamWidthTop(elAngle), 
MAX_RANGE);
    float[][] bottomRangeHeight = calcBeamPath(getBeamWidthBottom(elAngle), 
MAX_RANGE);

    Gridded2DSet topSet = new Gridded2DSet(new RealTupleType(range, height), 
topRangeHeight, 
                                                                 
topRangeHeight[0].length);
    Gridded2DSet bottomSet = new Gridded2DSet(new RealTupleType(range, height), 
bottomRangeHeight, 
                                                                 
bottomRangeHeight[0].length);
    SampledSet[] ss = new SampledSet[2];
    ss[0] = topSet;
    ss[1] = bottomSet;

    UnionSet beamWidthSet = new UnionSet(new RealTupleType(range, height), ss);

    return beamWidthSet;  
  }




  /**
   * Fill the current beam width
   */
  public Irregular2DSet fillBeamWidth(UnionSet uSet) throws VisADException, 
RemoteException
  {
    SampledSet[] sSets = uSet.getSets();

    Gridded2DSet topSet = (Gridded2DSet) sSets[0];
    Gridded2DSet bottomSet = (Gridded2DSet) sSets[1];

    float[][] topSetVals = topSet.getSamples();
    float[][] bottomSetVals = bottomSet.getSamples();


//  ####  Need a connector from bottom of beam to top of beam to create the 2D 
Fill.
//  ####  If beam width spans the upper right corner of the displap, add the 
corner point ("IF stmt")
    float con[][];
    if ( (topSetVals[0][topSetVals[0].length-1] < 398.0f) && 
         (bottomSetVals[0][bottomSetVals[0].length-1] >= 398.0f) &&
         (topSetVals[1][topSetVals[1].length-1] >= 24.7f) &&
         (bottomSetVals[1][bottomSetVals[1].length-1] < 24.7f) )
    {

      con = new float[][] {
      { bottomSetVals[0][bottomSetVals[0].length-1], 400.0f, 
topSetVals[0][topSetVals[0].length-1]+0.01f },
      { bottomSetVals[1][bottomSetVals[1].length-1]+0.01f, 25.0f, 
topSetVals[1][topSetVals[1].length-1]-0.01f }
         };
    }
    else
    {
      con =  new float[][]{ 
      { bottomSetVals[0][bottomSetVals[0].length-1], 
topSetVals[0][topSetVals[0].length-1]+0.01f },
      { bottomSetVals[1][bottomSetVals[1].length-1]+0.01f, 
topSetVals[1][topSetVals[1].length-1]-0.01f }
         };
    }

    float[][] tSetVals = new float[2][topSetVals[0].length];
    for (int i = 1; i < topSetVals[0].length; i++)
    {
      tSetVals[0][i-1] = topSetVals[0][topSetVals[0].length-i];
      tSetVals[1][i-1] = topSetVals[1][topSetVals[1].length-i];
    }
      tSetVals[0][tSetVals[0].length-1] = 
(topSetVals[0][0]+topSetVals[0][1])/2f;
      tSetVals[1][tSetVals[1].length-1] = 
(topSetVals[1][0]+topSetVals[1][1])/2f;
    
    int numVals = (bottomSetVals[0].length + tSetVals[0].length + 
con[0].length);
    float[][] allVals = new float[2][numVals];
    for (int p = 0; p < numVals; p++)
    {
      if (p < bottomSetVals[0].length)
      {
        allVals[0][p] = bottomSetVals[0][p];
        allVals[1][p] = bottomSetVals[1][p];
      }
      if (p < (bottomSetVals[0].length+con[0].length) && p >= 
bottomSetVals[0].length)
      {
        allVals[0][p] = con[0][p-bottomSetVals[0].length];
        allVals[1][p] = con[1][p-bottomSetVals[0].length];
      }
      if (p < numVals && p >= (bottomSetVals[0].length+con[0].length) )
      {
        allVals[0][p] = tSetVals[0][p-(bottomSetVals[0].length+con[0].length)];
        allVals[1][p] = tSetVals[1][p-(bottomSetVals[0].length+con[0].length)];

      }


    }
    
    Gridded2DSet g2s = new Gridded2DSet(rangeHeightType, allVals, numVals);
 
    Irregular2DSet filled = DelaunayCustom.fill(g2s);
 
    return filled;

  }



  /**
   *  Setters and Getters
   */
  public void setBeamPaths(FlatField[] p)
  { vcpPaths = p; }

  public void setBeamWidths(UnionSet[] p)
  { vcpWidths = p; }

  public void setBeamFills(Irregular2DSet[] p)
  { vcpFills = p; }

  public void setBeamLabels(Tuple[] p)
  { vcpLabels = p; }

  public FlatField[] getBeamPaths()
  { return vcpPaths; }

  public UnionSet[] getBeamWidths()
  { return vcpWidths; }

  public Irregular2DSet[] getBeamFills()
  { return vcpFills; }

  public Tuple[] getBeamLabels()
  { return vcpLabels; }

  public void setBeamPath(FlatField p)
  { singlePath = p; }

  public void setBeamWidth(UnionSet p)
  { singleWidth = p; }

  public void setBeamFill(Irregular2DSet p)
  { singleFill = p; }

  public void setBeamLabel(Tuple p)
  { singleLabel = p; }

  public FlatField getBeamPath()
  { return singlePath; }

  public UnionSet getBeamWidth()
  { return singleWidth; }

  public Irregular2DSet getBeamFill()
  { return singleFill; }

  public Tuple getBeamLabel()
  { return singleLabel; }


  public double getRadarElevation()
  { return radarElevation; }

  public void setEnteredBeamWidth(String bw)
  { enteredBeamWidth = Double.parseDouble(bw); }

  public double getEnteredBeamWidth()
  { return enteredBeamWidth; }

  public double getBeamWidthTop()
  {
    double bwHalf = (getEnteredBeamWidth()/2);
    return (elevationAngle + bwHalf);
  }

  public double getBeamWidthBottom()
  {
    double bwHalf = (getEnteredBeamWidth()/2);
    return (elevationAngle - bwHalf);
  }

  public double getBeamWidthTop(double elAn)
  {
    double bwHalf = (getEnteredBeamWidth()/2);
    return (elAn + bwHalf);
  }

  public double getBeamWidthBottom(double elAn)
  {
    double bwHalf = (getEnteredBeamWidth()/2);
    return (elAn - bwHalf);
  }

  public void setElevationAngle(double ea)
  { elevationAngle = ea; }

  public double getElevationAngle()
  { return elevationAngle; }

  public void setVCP(String els)
  {
    currentVCP = null;
    currentVCP = els;
  }

  public String getVCP()
  { return currentVCP; }

  public void setNumElevationAngles(int num)
  { numberOfElevationAnglesInCurrentVCP = num; }

  public int getNumElevationAngles()
  { return numberOfElevationAnglesInCurrentVCP; }

}