/* GridInt * Lab 7 * April 3, 2008 * Charles H C Meyer * CompSci 210 */ /* This program takes a text file with a header and terrain height data and * renders from it a picture using one of several diffrent color schemes * in a window that it opens. See the coments above each color scheme for detatils * on how they work. Best used in conjunction with another controller program, * since the main method only uses defaults. Note that the Grid is all in ints, * but that it will truncate float data into ints. */ import java.util.*; import java.io.*; import java.lang.*; import java.awt.*; import javax.swing.*; public class GridInt extends JFrame{ //the data from the headers private int ncols; //the # of coloumns private int nrows; //the # of rows private float cellSize; //??? private int noDataValue; //self explanatory //the actual grid private int[][] theGrid; private boolean renderGrid; //weather or not to paint the grid private int colorScheme; //the color scheme in use //the dimensions of the window private int windowWidth; private int windowHeight; //how much the grid is stretched to fit the window private float xStretch; private float yStretch; //the height that the min and max colour are asociated with private int maxHeight; private int minHeight; //some defaults private static final int MAX_HEIGHT_DEFAULT = 200; private static final int MIN_HEIGHT_DEFAULT = 0; private static final int COLOR_SCHEME_DEFAULT = 2; public GridInt (String fileName) { super("yeah"); //sets up some defualts renderGrid = false; maxHeight = MAX_HEIGHT_DEFAULT; minHeight = MIN_HEIGHT_DEFAULT; colorScheme = COLOR_SCHEME_DEFAULT; //sets the window to not vissible and to exit on close setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(false); //this set of code takes a file and puts a scanner on it File f = new File(fileName); Scanner sc = null; try { sc = new Scanner(f); //prints and error message if there is nos such file } catch (FileNotFoundException e) { System.err.println("File not found!"); System.exit(0); } //extracts information from the header setHeader(sc); //sets up defualt window size values to the terrain size windowWidth = ncols; windowHeight = nrows; xStretch = 1; yStretch = 1; setSize(windowWidth,windowHeight); //the grid that will hold the data theGrid = new int[nrows][ncols]; //counter int j = 0; //the row int k = 0; //the coloumn //a loop that adds the data from the scanner to the grid //terminates when it finishes the last row while (j < nrows) { theGrid[j][k] = (int) sc.nextFloat(); k++; //if k is at the end of the coloumn if ( k == ncols) { k = 0; j++; } } //a piece usefull for debugging, prints the array, although it is ill adivsed //to use it on large terrains /* for (int i = 0; i < theGrid.length; i++) { for (int m = 0; m < theGrid[i].length; m++) { System.out.print(theGrid[i][m]); } System.out.println(); } */ } //takes a scanner of a document and extracts the header information private void setHeader (Scanner sc) { //these are tripped when the method finds the elements boolean hasNCols = false; boolean hasNRows = false; boolean hasCellSize = false; boolean hasNoDataValue = false; //scans through the header, asigning values where they are needed //stops when it hits two numbers in a row while (!sc.hasNextFloat()) { String theLine = sc.next(); //found the ncols if (theLine.equals("ncols")) { if (hasNCols == false) { ncols = sc.nextInt(); hasNCols = true; } else { //if this is a duplicate System.err.println("error with header ncols"); } } //founds the nrows else if (theLine.equals("nrows")) { if (hasNRows == false) { nrows = sc.nextInt(); hasNRows = true; } else { System.err.println("error with header nrows"); } } //found the cell size else if (theLine.equals("cellsize")) { if (hasCellSize == false) { cellSize = sc.nextFloat(); hasCellSize = true; } else { System.err.println("error with header cellsize"); } } // found the no data value else if (theLine.equals("NODATA_value")) { if (hasNoDataValue == false) { noDataValue = sc.nextInt(); hasNoDataValue = true; } else { System.err.println("error with header NODATA_value"); } } //if the value was something else else { sc.next(); } } //if a piece of the header is missing if (!(hasNCols && hasNRows && hasCellSize && hasNoDataValue)) { System.err.println("error with header insuficient data"); } } //changes the window size public void setWindow(int newWindowWidth, int newWindowHeight) { windowWidth = newWindowWidth; windowHeight = newWindowHeight; //sets the new size setSize(windowWidth,windowHeight); //factors that the grid is stretched to to acomidate the window xStretch = windowWidth/ncols; yStretch = windowHeight/nrows; repaint(); } //self explanatory public void setMinHeight(int newHeight) { minHeight = newHeight; repaint(); } //self explanatory public void setMaxHeight(int newHeight) { maxHeight = newHeight; repaint(); } //self explanatory public void setColorScheme(int newScheme) { colorScheme = newScheme; repaint(); } public void paint(Graphics window) { super.paint(window); //goes through the array, drawing lines from all but the far most right coloumn and //the bottom row, wich are ignored on the theory that they are to small to matter if (theGrid != null && renderGrid) { for (int j = 0; j < theGrid.length-1; j++) { for (int k = 0; k < theGrid[j].length-1; k++) { //draws a line from the point to one point to the left window.setColor(getColor((theGrid[j][k] + theGrid[j][k+1])/2)); window.drawLine((int)(k*xStretch),(int)(j*yStretch), (int)((k+1)*xStretch),(int)(j*yStretch)); //draws a line to one point beneath window.setColor(getColor((theGrid[j][k] + theGrid[j+1][k+1])/2)); window.drawLine((int)(k*xStretch),(int)(j*yStretch), (int)((k+1)*xStretch),(int)((j+1)*yStretch)); // draws the diagonal to the bottom right window.setColor(getColor((theGrid[j][k] + theGrid[j+1][k])/2)); window.drawLine((int)(k*xStretch),(int)(j*yStretch), (int)(k*xStretch),(int)((j+1)*yStretch)); } } } } //this is used to get the apropriate color for a height private Color getColor(float height) { //one of these is the correct colorscheme if (colorScheme == 1) { return getColor1(height); } else if (colorScheme == 2) { return getColor2(height); } else if (colorScheme == 3) { return getColor3(height); } else { //or if none of them are it goes to a default and sends an error System.err.println("Error with color scheme choice, defaulting to " + COLOR_SCHEME_DEFAULT); colorScheme = COLOR_SCHEME_DEFAULT; } //the default return getColor2(height); } //this sets up the color on a grayscale private Color getColor1(float height) { //sets up the color on a grayscale float numColor = (height-minHeight)/(maxHeight-minHeight); //if the color is to high if (numColor > 1) { numColor = 1; } //if it is to low if (numColor < 0) { numColor = 0; } Color toReturn = new Color(numColor,numColor,numColor); return toReturn; } //my favorite, this gradually shifts from red to green to blue private Color getColor2(float height) { //the components of the color, given a value to make java compile float ColorR = 0; float ColorG = 0; float ColorB = 0; //goes to black if there is no data if (height == noDataValue) { ColorR = 1; ColorG = 1; ColorB = 1; } else if (height < minHeight) {//if the data is to low ColorR = 1; ColorG = 0; ColorB = 0; } //if the data is in the lower half of the range else if (height <= (maxHeight+minHeight)/2) { //starts at 1 and linearly decreases to 0 ColorR = 1 - (height-minHeight)*2/(maxHeight - minHeight); //starts at 0 and linearly increases to 1 ColorG = (height-minHeight)*2/(maxHeight - minHeight); ColorB = 0; } //if it is in the upper half else if (height <= maxHeight) { ColorR = 0; //starts at 0 and linearly increases to 1 ColorG = (height-minHeight)*2/(maxHeight - minHeight)-1; //starts at 1 and linearly decreases to 0 ColorB = 2 - (height-minHeight)*2/(maxHeight - minHeight); } else if (height >maxHeight) { //if the value is above the range ColorR = 0; ColorG = 0; ColorB = 1; } else { //should never happen, indicates a problem with the code assert false; } //debuggin line, prints every color //System.out.println("h" + height + " r " + ColorR + " G " + ColorG +" B " + ColorB); Color toReturn = new Color(ColorR, ColorG, ColorB); return toReturn; } //a third system, everything zeroes between colors, goes from //red, to zeros, to green, to zeroes, to blue, all lineraly private Color getColor3(float height) { float ColorR = 0; float ColorG = 0; float ColorB = 0; if (height == noDataValue) {//the no data value ColorR = 1; ColorG = 1; ColorB = 1; } else if (height < minHeight) {//under the range ColorR = 0; ColorG = 0; ColorB = 0; } else if (height <= (maxHeight+minHeight*5)/6) { //increases red ColorR = 6*(height-minHeight)/(maxHeight-minHeight); ColorG = 0; ColorB = 0; } else if (height <= (maxHeight+minHeight*2)/3) {//decreases red ColorR = 2-6*(height-minHeight)/(maxHeight-minHeight); ColorG = 0; ColorB = 0; } else if (height <= (maxHeight+minHeight)/2) {//increases green ColorR = 0; ColorG = 6*(height-minHeight)/(maxHeight-minHeight) - 2; ColorB = 0; } else if (height <= (maxHeight*2+minHeight)/3) {//decreases green ColorR = 0; ColorG = 4 - 6*(height-minHeight)/(maxHeight-minHeight); ColorB = 0; } else if (height <= (maxHeight*5+minHeight)/6) {//increses blue ColorR = 0; ColorG = 0; ColorB = 6*(height-minHeight)/(maxHeight-minHeight) - 4; } else if (height <= maxHeight) {//decreses blue ColorR = 0; ColorG = 0; ColorB = 6 - 6*(height-minHeight)/(maxHeight-minHeight); } else if (height >maxHeight) {//above the range ColorR = 0; ColorG = 0; ColorB = 0; } //de buggin line, prints every color //System.out.println("h" + height + " r " + ColorR + " G " + ColorG +" B " + ColorB); Color toReturn = new Color(ColorR, ColorG, ColorB); return toReturn; } //creates the grid using default values and args[0] as the file public static void main(String[] args) { GridInt theGrid = new GridInt (args[0]); theGrid.renderGrid(); } //displays the grid and unhides the window, //usefull to forestall paint calculations until all variables are set public void renderGrid () { renderGrid = true; setVisible(true); } }