|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 4 of 6
Now it is just a matter of using a set of nested for loops to read in the B records one at a time (each representing one column of data), and the row data itself. When the process
is complete, the streams close. All elevation data is now stored in the 2D elevations array. The elevations array is an integer array since each elevation is to the nearest meter. The source for DemFile is shown below:
import java.io.*;
/**
* This class is a specialization of the ElevationFile class created
* specifically to load DEM format data from the USGS archives.
*
* @author Mark Pendergast
* @version 1.0 February 2003
* @see ElevationFile
*/
public class DemFile extends ElevationFile {
public static final int ARECORD_LENGTH = 1024; public static final int QUADRANGLE_NAME_LENGTH = 144; public static final int MIN_ARECORD_TOKENS = 39;
/**
* Create DemFile object from data contained in specified file.
*
* @param aFileName name of the DEM file to load. File name should be a
* fully qualified file name.
* @exception IllegalArgumnetException thrown whenever an invalid data
* file is given as an argument.
*/
public DemFile(String aFileName) throws IllegalArgumentException
{
try{
char[] Arecord = new char[ARECORD_LENGTH];
fileName = new String(aFileName);
FileReader file = new FileReader(fileName);
BufferedReader bReader = new BufferedReader(file);
//
// Read and parse out A record.
//
if(bReader.read(Arecord,0,ARECORD_LENGTH) == -1)
{
bReader.close();
System.out.println("Invalid file format (bad arecord) : "+fileName);
throw(new IllegalArgumentException("Invalid file format : "+ fileName));
}
quadrangleName = new String(Arecord, 0, QUADRANGLE_NAME_LENGTH);
quadrangleName = quadrangleName.trim();
minElevation = (int)parseDemDouble(new String(Arecord,738,24));
maxElevation = (int)parseDemDouble(new String(Arecord,762,24));
groundCoordinates.sw[GroundCoordinates.LONGITUDE] =
Math.abs(parseDemDouble(new String(Arecord,546,24)));
groundCoordinates.sw[GroundCoordinates.LATITUDE] =
Math.abs(parseDemDouble(new String(Arecord,570,24)));
groundCoordinates.nw[GroundCoordinates.LONGITUDE] =
Math.abs(parseDemDouble(new String(Arecord,594,24)));
groundCoordinates.nw[GroundCoordinates.LATITUDE] =
Math.abs(parseDemDouble(new String(Arecord,618,24)));
groundCoordinates.ne[GroundCoordinates.LONGITUDE] =
Math.abs(parseDemDouble(new String(Arecord,642,24)));
groundCoordinates.ne[GroundCoordinates.LATITUDE] =
Math.abs(parseDemDouble(new String(Arecord,666,24)));
groundCoordinates.se[GroundCoordinates.LONGITUDE] =
Math.abs(parseDemDouble(new String(Arecord,690,24)));
groundCoordinates.se[GroundCoordinates.LATITUDE] =
Math.abs(parseDemDouble(new String(Arecord,714,24)));
nColumns = (int)parseDemDouble(new String(Arecord,858,6));
//
// Use a StreamTokenizer to parse B records, one record for each column.
// Set the StreamTokenizer to use a space a delimiter and convert all
// tokens to strings.
//
StreamTokenizer st = new StreamTokenizer(bReader); // Stream prepositioned to start of B record.
st.resetSyntax();
st.whitespaceChars(' ',' ');
st.wordChars(' '+1,'z');
for(int column = 0; column < nColumns; column++)
{
int ttype;
double rowCoordinateLat, rowCoordinateLong;
st.nextToken(); // Skip row ID.
st.nextToken(); // Skip column ID.
ttype = st.nextToken(); // Number of rows.
nRows = (int)parseDemInt(st.sval);
if(elevations == null) // Allocate array if necessary.
elevations = new int[nRows][nColumns];
for(int i=0; i < 6; i++) // Skip 6 fields.
st.nextToken();
for(int row = 0; row<nRows; row++) // Read in elevation data.
{
st.nextToken();
elevations[row][column]= parseDemInt(st.sval);
}
}
bReader.close();
} // End try.
catch(IOException e){
System.out.println("IE Exception when loading from [" + fileName + "] error: " +
e.getMessage());
throw new IllegalArgumentException("File I/O failure : "+fileName);
}
catch(NumberFormatException e){
System.out.println("NumberFormat Exception when loading from [" + fileName + "] ");
throw new IllegalArgumentException("Invalid file format : "+fileName);
}
System.gc(); // Clean out memory.
}
/**
* This method parses a double from a string. Note, DEM data uses
* the old FORTRAN notation for storing doubles using a 'D' instead of an
* 'E'.
* @param in string to parse
* @return double value from string
* @exception NumberFormatException thrown when string is not a valid double
*/
public double parseDemDouble(String in) throws NumberFormatException
{
String st = in.replace('D','E'); // Convert FORTRAN format to modern.
return Double.parseDouble(st.trim());
}
public int parseDemInt(String in) throws NumberFormatException
{
String st = in.replace('D','E'); // Convert FORTRAN format to modern.
return Integer.parseInt(st.trim());
}
}
Once the DEM file has loaded, the elevation data can convert into Java 3D geometry objects. As stated previously, to support
fly-through and other real-time screen update sequences, we must use the most efficient data structures and level-of-detail
optimizations. My experience has shown that TriangleStripArrays using interleaved-by-reference data handling is the most efficient in terms of memory and processor usage. While modeling
the entire terrain model as a single TriangleStripArray object is possible, that does not allow you to take full advantage of Java 3D's level-of-detail feature. For LOD to work,
you must have some distant objects drawn at low resolution, and closer objects drawn at full resolution. Therefore, the region
divides into numerous segments; in my demonstration program, I divided the region into a six-by-six grid, as illustrated in
Figure 3.
Archived Discussions (Read only)