// ********************************************************************** // // <copyright> // // BBN Technologies // 10 Moulton Street // Cambridge, MA 02138 // (617) 873-8000 // // Copyright (C) BBNT Solutions LLC. All rights reserved. // // </copyright> // ********************************************************************** // // $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/layer/dted/DTEDFrame.java,v $ // $RCSfile: DTEDFrame.java,v $ // $Revision: 1.8 $ // $Date: 2008/02/29 00:51:10 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.layer.dted; import java.awt.Color; import com.bbn.openmap.dataAccess.dted.DTEDFrame; import com.bbn.openmap.omGraphics.OMGraphic; import com.bbn.openmap.omGraphics.OMRaster; import com.bbn.openmap.omGraphics.OMRasterObject; import com.bbn.openmap.proj.CADRG; import com.bbn.openmap.proj.Projection; import com.bbn.openmap.proj.coords.LatLonPoint; import com.bbn.openmap.util.Debug; /** * The DTEDSubframedFrame is the representation of the DTED (Digital Terrain * Elevation Data) data from a single dted data file. It keeps track of all the * attribute information of it's data, and also maintains an array of images * (DTEDFrameSubframe) that represent views of the elevation posts. */ public class DTEDSubframedFrame extends DTEDFrame { /** The colortable used to create the images. */ public DTEDFrameColorTable colorTable; /** The subframe presentation attributes. */ public DTEDFrameSubframeInfo subframeInfo; // master /** * The frame image is divided into 200x200 pixel subframes, with a leftover * frame at the end. This is how many horizontal subframes there are. */ public int number_horiz_subframes; /** * The frame image is divided into 200x200 pixel subframes, with a leftover * frame at the end. This is how many vertical subframes there are. */ public int number_vert_subframes; /** The image array for the subframes. */ public DTEDFrameSubframe subframes[][]; // //////////////// // Administrative methods // //////////////// /** * Simplest constructor. * * @param filePath complete path to the DTED frame. */ public DTEDSubframedFrame(String filePath) { this(filePath, null, null, false); } /** * Constructor with colortable and presentation information. * * @param filePath complete path to the DTED frame. * @param cTable the colortable to use for the images. * @param info presentation parameters. */ public DTEDSubframedFrame(String filePath, DTEDFrameColorTable cTable, DTEDFrameSubframeInfo info) { this(filePath, cTable, info, false); } /** * Constructor with colortable and presentation information. * * @param filePath complete path to the DTED frame. * @param readWholeFile If true, all of the elevation data will be read at * load time. If false, elevation post data will be read in per * longitude column depending on the need. False is recommended for * DTEd level 1 and 2. */ public DTEDSubframedFrame(String filePath, boolean readWholeFile) { this(filePath, null, null, readWholeFile); } /** * Constructor with colortable and presentation information. * * @param filePath complete path to the DTED frame. * @param cTable the colortable to use for the images. * @param info presentation parameters. * @param readWholeFile If true, all of the elevation data will be read at * load time. If false, elevation post data will be read in per * longitude column depending on the need. False is recommended for * DTED level 1 and 2. */ public DTEDSubframedFrame(String filePath, DTEDFrameColorTable cTable, DTEDFrameSubframeInfo info, boolean readWholeFile) { super(filePath, readWholeFile); colorTable = cTable; subframeInfo = info; } public void setColorTable(DTEDFrameColorTable c_Table) { colorTable = c_Table; } public DTEDFrameColorTable getColorTable() { return colorTable; } /** * Sets the subframe array. Blows away any images that may already be there. */ public void initSubframes(int numHorizSubframes, int numVertSubframes) { number_horiz_subframes = numHorizSubframes; number_vert_subframes = numVertSubframes; subframes = new DTEDFrameSubframe[numHorizSubframes][numVertSubframes]; if (Debug.debugging("dted")) { Debug.output("///////// DTEDFrame: subframe array initialized, " + numHorizSubframes + "x" + numVertSubframes); } } /** * If you just want to get an image for the DTEDFrame, then call this. One * OMRaster for the entire DTEDFrame will be returned, with the default * rendering parameters (Colored shading) and the default colortable. Use * the other getOMRaster method if you want something different. This method * actually calls that other method, so read the documentation for that as * well. * * @param proj EqualArc projection to use to create image. * @return raster image to display in OpenMap. */ public OMGraphic getImage(Projection proj) { return getImage(null, null, proj); } /** * If you just want to get an image for the DTEDFrame, then call this. One * OMRaster for the entire DTEDFrame will be returned. In the * DTEDFrameSubframeInfo, you need to set the color type and all the * parameters that are assiociated with the rendering parameters. The * projection parameters of the DFSI (image height, width, pixel intervals) * will be set in this method based on the projection. If you want a * different sized image, scale the thing you get back from this method, or * change the scale of the projection that is passed in. Calling this method * will cause the DTEDFrame subframe cache to reset itself to hold one * subframe covering the entire frame. Just so you know. * * @param dfsi the DTEDFrameSubframeInfo describing the subframe. * @param colortable the colortable to use when building the image. * @return raster image to display in OpenMap. * @param proj EqualArc projection to use to create image. */ public OMGraphic getImage(DTEDFrameSubframeInfo dfsi, DTEDFrameColorTable colortable, Projection proj) { if (proj == null) { Debug.error("DTEDFrame.getOMRaster: need projection to create image."); return null; } if (colortable == null) { colortable = new DTEDFrameColorTable(); } if (dfsi == null) { dfsi = new DTEDFrameSubframeInfo(DTEDFrameSubframe.COLOREDSHADING, DTEDFrameSubframe.DEFAULT_BANDHEIGHT, DTEDFrameSubframe.LEVEL_1, // Doesn't // matter DTEDFrameSubframe.DEFAULT_SLOPE_ADJUST); } CADRG cadrg = CADRG.convertProjection(proj); dfsi.xPixInterval = 360 / cadrg.getXPixConstant(); // degrees/pixel dfsi.yPixInterval = 90 / cadrg.getYPixConstant(); dfsi.height = (int) (1 / dfsi.yPixInterval); dfsi.width = (int) (1 / dfsi.xPixInterval); // Will trigger the right thing in getSubframeOMRaster; subframes = null; return getSubframeImage(dfsi, colortable, proj); } /** * Return the subframe image as described in the DTEDFrameSubframeInfo. This * is called by the DTEDCacheHandler, which has in turn set the * DTEDFrameSubframeInfo parameters to match the projection parameters. This * turns out to be kinda important. * * @param dfsi the DTEDFrameSubframeInfo describing the subframe. * @param colortable the colortable to use when building the image. * @return raster image to display in OpenMap. */ public OMGraphic getSubframeImage(DTEDFrameSubframeInfo dfsi, DTEDFrameColorTable colortable, Projection proj) { if (!frame_is_valid) return null; OMGraphic raster = null; if (dfsi.viewType == DTEDFrameSubframe.NOSHADING) return null; if (dfsi.viewType == DTEDFrameSubframe.COLOREDSHADING) colortable.setGreyScale(false); else colortable.setGreyScale(true); float lat_origin = dfsi.lat; float lon_origin = dfsi.lon; if (subframes == null) { // Need to set a couple of things up if the DTEDFrameCache // isn't being used to set up the subframe information in // the dfsi. initSubframes(1, 1); // NOTE!! The algorithm uses the coordinates of the top // left corner as a reference!!!!!!!! lat_origin = dsi.lat_origin + 1; lon_origin = dsi.lon_origin; } DTEDFrameSubframe subframe = subframes[dfsi.subx][dfsi.suby]; if (Debug.debugging("dteddetail")) { Debug.output("Subframe lat/lon => lat= " + lat_origin + " vs. " + dfsi.lat + " lon= " + lon_origin + " vs. " + dfsi.lon + " subx = " + dfsi.subx + " suby = " + dfsi.suby); Debug.output("Height/width of subframe => height= " + dfsi.height + " width= " + dfsi.width); } if (subframe != null) { raster = subframe.getImageIfCurrent(proj, dfsi); if (raster != null) { if (Debug.debugging("dted")) { Debug.output("######## DTEDFrame: returning cached subframe"); } return raster; } if (Debug.debugging("dted")) { Debug.output(" *** DTEDFrame: changing image of cached subframe"); } /* * If there is an image, the types are different and it needs to be * redrawn */ subframe.dfsi = dfsi.makeClone(); } else { if (Debug.debugging("dted")) { Debug.output(" +++ DTEDFrame: creating subframe"); } subframe = new DTEDFrameSubframe(dfsi); subframes[dfsi.subx][dfsi.suby] = subframe; } // lat/lon_post_intervals are *10 too big - // extra 0 in // 36000 to counteract // start in lower left of subframe double start_lat_index = (lat_origin - (double) dsi.sw_lat) * 36000.0 / (double) uhl.lat_post_interval; double start_lon_index = (lon_origin - (double) dsi.sw_lon) * 36000.0 / (double) uhl.lon_post_interval; double end_lat_index = ((lat_origin - ((double) dfsi.height * dfsi.yPixInterval)) - (double) dsi.sw_lat) * 36000.0 / (double) uhl.lat_post_interval; double end_lon_index = ((lon_origin + ((double) dfsi.width * dfsi.xPixInterval)) - (double) dsi.sw_lon) * 36000.0 / (double) uhl.lon_post_interval; double lat_interval = (start_lat_index - end_lat_index) / (double) dfsi.height; double lon_interval = (end_lon_index - start_lon_index) / (double) dfsi.width; if (Debug.debugging("dteddetail")) Debug.output(" start_lat_index => " + start_lat_index + "\n" + " end_lat_index => " + end_lat_index + "\n" + " start_lon_index => " + start_lon_index + "\n" + " end_lon_index => " + end_lon_index + "\n" + " lat_interval => " + lat_interval + "\n" + " lon_interval => " + lon_interval); short e1, e2; short xc = 0; short yc = 0; short xnw = 0; short ynw = 0; short xse = 0; short yse = 0; double slope; double distance = 1.0; float value = 0.0f; int assignment = 0; double modifier = (double) 0; double xw_offset = 0; double xe_offset = 0; double yn_offset = 0; double ys_offset = 0; int elevation = (int) 0; // Calculations needed once for slope shading if (dfsi.viewType == DTEDFrameSubframe.SLOPESHADING || (dfsi.viewType == DTEDFrameSubframe.COLOREDSHADING && colortable.colors.length > DTEDFrameColorTable.NUM_ELEVATION_COLORS)) { // to get to the right part of the frame, kind of like a // subframe // indexing thing xw_offset = start_lon_index - Math.ceil(lon_interval); xe_offset = start_lon_index + Math.ceil(lon_interval); yn_offset = start_lat_index + Math.ceil(lat_interval); ys_offset = start_lat_index - Math.ceil(lat_interval); switch (dfsi.dtedLevel) { // larger numbers make less contrast case 0: modifier = (double) 4; break;// 1000 ideal case 1: modifier = (double) .02; break;// 2 ideal case 2: modifier = (double) .0001; break; case 3: modifier = (double) .000001; break; default: modifier = (double) 1; } // With more colors, contrast tends to be a little light // for the // default - brighten it up more if (colortable.colors.length > 215) modifier /= 10; for (int h = dfsi.slopeAdjust; h < 5; h++) modifier *= 10; distance = Math.sqrt((modifier * lon_interval * lon_interval) + (modifier * lat_interval * lat_interval)); } ImageData imageData = ImageData.getImageData(dfsi.colorModel, dfsi.width, dfsi.height, colortable.colors); for (short x = 0; x < dfsi.width; x++) { // used for both elevation banding and slope xc = (short) (start_lon_index + ((x) * lon_interval)); if (xc < 0) xc = 0; if (xc > dsi.num_lon_points - 1) xc = (short) (dsi.num_lon_points - 1); if ((elevations[xc] == null) && !readDataRecord(xc)) { Debug.error("DTEDFrame: Problem reading lat point line in data record"); return null; } if (dfsi.viewType == DTEDFrameSubframe.SLOPESHADING || (dfsi.viewType == DTEDFrameSubframe.COLOREDSHADING && colortable.colors.length > DTEDFrameColorTable.NUM_ELEVATION_COLORS)) { // This is actually finding the right x post for this // pixel, // within the subframe measurements. xnw = (short) (xw_offset + Math.floor(x * lon_interval)); xse = (short) (xe_offset + Math.floor(x * lon_interval)); // trying to smooth out the edge of the frame if (xc == 0 || xnw < 0) { xnw = xc; xse = (short) (xnw + 2.0 * Math.ceil(lon_interval)); } if (xc == dsi.num_lon_points - 1 || xse > dsi.num_lon_points - 1) { xse = (short) (dsi.num_lon_points - 1); xnw = (short) (xse - 2.0 * Math.ceil(lon_interval)); } if (((elevations[xnw] == null) && !readDataRecord(xnw)) || ((elevations[xse] == null) && !readDataRecord(xse))) { Debug.error("DTEDFrame: Problem reading lat point line in data record"); return null; } } // Now, calculate the data and assign the pixels based on // y for (short y = 0; y < dfsi.height; y++) { // used for elevation band and slope yc = (short) (start_lat_index - ((y) * lat_interval)); if (yc < 0) yc = 0; elevation = (int) elevations[xc][yc]; // elevation shading if (dfsi.viewType == DTEDFrameSubframe.METERSHADING || dfsi.viewType == DTEDFrameSubframe.FEETSHADING) { // Just use the top two-thirds of the colors if (elevation == 0) assignment = 0; // color water Blue else { if (elevation < 0) elevation *= -1; // Death Valley if (dfsi.viewType == DTEDFrameSubframe.FEETSHADING) elevation = (int) (elevation * 3.2); // Start at the darkest color, and then go up // through the // colormap for each band height, the start // back at the // darkest when you get to the last color. To // make this // more useful, I limit the number of colors // (10) used - if // there isn;t enough contrast between the // colors, you can't // see the bands. The contrast adjustment in // 24-bit color // mode(216 colors) lets you add a few colors. if (colortable.colors.length < 216) { try { assignment = (int) ((elevation / dfsi.bandHeight) % (colortable.colors.length - 6) + 6); } catch (java.lang.ArithmeticException ae) { assignment = 1; } } else { try { assignment = (int) (((elevation / dfsi.bandHeight) % (10 - 2 * (3 - dfsi.slopeAdjust)) * (colortable.colors.length / (10 - 2 * (3 - dfsi.slopeAdjust)))) + 6); } catch (java.lang.ArithmeticException ae) { assignment = 1; } } } imageData.set(x, y, assignment); } // Slope shading else if (dfsi.viewType == DTEDFrameSubframe.SLOPESHADING || (dfsi.viewType == DTEDFrameSubframe.COLOREDSHADING && colortable.colors.length > DTEDFrameColorTable.NUM_ELEVATION_COLORS)) { // find the y post indexes within the subframe ynw = (short) (yn_offset - Math.floor(y * lat_interval)); yse = (short) (ys_offset - Math.floor(y * lat_interval)); // trying to smooth out the edge of the frame by // handling the // frame limits if (yse < 0) yse = 0; if (yc == dsi.num_lat_lines - 1 || ynw > dsi.num_lat_lines - 1) ynw = (short) (dsi.num_lat_lines - 1); e2 = elevations[xse][yse]; // down & right // elevation e1 = elevations[xnw][ynw]; // up and left // elevation slope = (e2 - e1) / distance; // slope relative to // nw sun // colormap value darker for negative slopes, // brighter for // positive slopes if (dfsi.viewType == DTEDFrameSubframe.COLOREDSHADING) { assignment = 1; elevation = (int) (elevation * 3.2);// feet for (int l = 1; l < DTEDFrameColorTable.NUM_ELEVATION_COLORS; l++) if (elevation <= colortable.elevation_color_cutoff[l]) { if (slope < 0) assignment = (int) (l + DTEDFrameColorTable.NUM_ELEVATION_COLORS); else if (slope > 0) assignment = (int) (l + (DTEDFrameColorTable.NUM_ELEVATION_COLORS * 2)); else assignment = (int) l; break; } if (elevation == 0) assignment = 0; imageData.set(x, y, assignment); } else { value = (float) (((colortable.colors.length - 1) / 2) + slope); // not water, but close in the colormap - max // dark if (slope != 0 && value < 1) value = 1; if (elevation == 0) value = 0; // water?!? if (value > (colortable.colors.length - 1)) value = colortable.colors.length - 1; // max // bright assignment = (int) value; imageData.set(x, y, assignment); } } // Subframe outlines - different colors for each side // of the frame // This is really for debugging purposes, really. else if (dfsi.viewType == DTEDFrameSubframe.BOUNDARYSHADING) { int c; if (x < 1) c = 1; else if (x > dfsi.width - 2) c = 12; else if (y < 1) c = 1; else if (y > dfsi.height - 2) c = 12; else c = 7; imageData.set(x, y, c); } else if (dfsi.viewType == DTEDFrameSubframe.COLOREDSHADING) { assignment = 1; elevation = (int) (elevation * 3.2);// feet for (int l = 1; l < DTEDFrameColorTable.NUM_ELEVATION_COLORS; l++) if (elevation <= colortable.elevation_color_cutoff[l]) { assignment = (int) l; break; } if (elevation == 0) assignment = 0; if (elevation < 0) assignment = 1; if (elevation > 33000) assignment = 1; imageData.set(x, y, assignment); } } } imageData.updateData(subframe); if (Debug.debugging("dteddetail")) Debug.output("DTEDFrame: leaving raster"); return subframe.getImage(proj); } public static void main(String args[]) { Debug.init(); if (args.length < 1) { System.out.println("DTEDFrame: Need a path/filename"); System.exit(0); } System.out.println("DTEDFrame: " + args[0]); DTEDSubframedFrame df = new DTEDSubframedFrame(args[0]); if (df.frame_is_valid) { System.out.println(df.uhl); System.out.println(df.dsi); System.out.println(df.acc); // int startx = 5; // int starty = 6; // int endx = 10; // int endy = 30; // short[][] e = df.getElevations(startx, starty, endx, // endy); // for (int i = e[0].length-1; i >= 0; i--) { // for (int j = 0; j < e.length; j++) { // System.out.print(e[j][i] + " "); // } // System.out.println(); // } } float lat = df.dsi.lat_origin + .5f; float lon = df.dsi.lon_origin + .5f; CADRG crg = new CADRG(new LatLonPoint.Double(lat, lon), 1500000, 600, 600); final OMGraphic ras = df.getImage(crg); // Pushes the image to the left top of the frame. if (ras instanceof OMRaster) { crg.setHeight(((OMRaster) ras).getHeight()); crg.setWidth(((OMRaster) ras).getWidth()); } ras.generate(crg); java.awt.Frame window = new java.awt.Frame(args[0]) { public void paint(java.awt.Graphics g) { if (ras != null) { ras.render(g); } } }; window.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent e) { // need a shutdown event to notify other gui beans and // then exit. System.exit(0); } }); window.setSize(crg.getWidth(), crg.getHeight()); window.setVisible(true); window.repaint(); } protected static abstract class ImageData { protected abstract void set(short x, short y, int value); protected abstract void updateData(DTEDFrameSubframe dfs); int width = 0; int height = 0; Color[] colors; protected ImageData(int w, int h, Color[] colors) { this.width = w; this.height = h; this.colors = colors; } protected static ImageData getImageData(int colorModel, int width, int height, Color[] colors) { if (colorModel == OMRasterObject.COLORMODEL_DIRECT) { return new Pixel(width, height, colors); } else { return new Byte(width, height, colors); } } protected static class Pixel extends ImageData { int[] pixels; int ranColor; protected Pixel(int w, int h, Color[] colors) { super(w, h, colors); pixels = new int[w * h]; int red = (int) (Math.random() * 255); int green = (int) (Math.random() * 255); int blue = (int) (Math.random() * 255); Color color = new Color(red, green, blue); ranColor = color.getRGB(); } protected void set(short x, short y, int value) { pixels[(y * width) + x] = colors[value].getRGB(); // pixels[(y * width) + x] = ranColor; } protected void updateData(DTEDFrameSubframe dfs) { dfs.setPixels(pixels); } } protected static class Byte extends ImageData { byte[] bytes; protected Byte(int w, int h, Color[] colors) { super(w, h, colors); bytes = new byte[w * h]; } protected void set(short x, short y, int value) { bytes[(y * width) + x] = (byte) value; } protected void updateData(DTEDFrameSubframe dfs) { dfs.setBitsAndColors(bytes, colors); } } } }