Package com.bbn.openmap.layer.dted

Source Code of com.bbn.openmap.layer.dted.DTEDFrame

// **********************************************************************
//
// <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.3.2.5 $
// $Date: 2008/02/29 00:51:29 $
// $Author: dietrick $
//
// **********************************************************************

package com.bbn.openmap.layer.dted;

import java.io.FileNotFoundException;
import java.io.IOException;

import com.bbn.openmap.io.BinaryBufferedFile;
import com.bbn.openmap.io.BinaryFile;
import com.bbn.openmap.io.Closable;
import com.bbn.openmap.io.FormatException;
import com.bbn.openmap.omGraphics.OMRaster;
import com.bbn.openmap.omGraphics.OMRasterObject;
import com.bbn.openmap.proj.CADRG;
import com.bbn.openmap.proj.EqualArc;
import com.bbn.openmap.util.Debug;

/**
* The DTEDFrame 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 DTEDFrame implements Closable {

    public final static int UHL_SIZE = 80;
    public final static int DSI_SIZE = 648;
    public final static int ACC_SIZE = 2700;
    public final static int ACC_SR_SIZE = 284;
    /** The binary buffered file to read the data from the file. */
    protected BinaryFile binFile;
    /** The path to the frame, including the frame name. */
    protected String path;
    /**
     * The array of elevation posts. Note: the 0 index of the array in
     * both directions is in the lower left corner of the matrix. As
     * you increase indexes in both dimensions, you go up-right.
     */
    protected short[][] elevations; // elevation posts

    /** Data set indentification section of the file. */
    public DTEDFrameDSI dsi;
    /** User header label section of the file. */
    public DTEDFrameUHL uhl;
    /** The colortable used to create the images. */
    public DTEDFrameColorTable colorTable;
    /** The subframe presentation attributes. */
    public DTEDFrameSubframeInfo subframeInfo; // master
    /** Validity flag for the quality of the data file. */
    public boolean frame_is_valid = false;

    /**
     * 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 DTEDFrame(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 DTEDFrame(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 DTEDFrame(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 DTEDFrame(String filePath, DTEDFrameColorTable cTable,
            DTEDFrameSubframeInfo info, boolean readWholeFile) {

        try {
            binFile = new BinaryBufferedFile(filePath);

            read(binFile, readWholeFile);
            if (readWholeFile)
                close(true);
            else
                BinaryFile.addClosable(this);

        } catch (FileNotFoundException e) {
            Debug.error("DTEDFrame: file " + filePath + " not found");
        } catch (java.io.IOException e) {
            Debug.error("DTEDFrame: File IO Error!\n" + e.toString());
        }

        colorTable = cTable;
        subframeInfo = info;
        path = filePath;
    }

    public void setColorTable(DTEDFrameColorTable c_Table) {
        colorTable = c_Table;
    }

    public DTEDFrameColorTable getColorTable() {
        return colorTable;
    }

    /**
     * Reads the DTED frame file. Assumes that the File f is
     * valid/exists.
     *
     * @param binFile the binary buffere file opened on the DTED frame
     *        file
     * @param readWholeFile flag controlling whether all the row data
     *        is read at this time. Otherwise, the rows are read as
     *        needed.
     */
    protected void read(BinaryFile binFile, boolean readWholeFile) {
        binFile.byteOrder(true); //boolean msbfirst
        dsi = new DTEDFrameDSI(binFile);
        uhl = new DTEDFrameUHL(binFile);
        //  Allocate just the columns now - we'll do the rows as
        // needed...
        elevations = new short[uhl.num_lon_lines][];
        if (readWholeFile)
            read_data_records();
        frame_is_valid = true;
    }

    /**
     * This must get called to break a reference cycle that prevents
     * the garbage collection of frames.
     */
    public void dispose() {
        //System.out.println("DTED Frame Disposed " + me);
        this.close(true);
        BinaryFile.removeClosable(this);
    }

    //     public void finalize() {
    //         System.out.println("DTED Frame Finalized!" + me);
    //     }

    /**
     * Part of the Closable interface. Closes the BinaryFile pointer,
     * because someone else needs another file open, and the system
     * needs a file pointer. Sets the binFile variable to null.
     */
    public boolean close(boolean done) {
        try {
            binFile.close();
            binFile = null;
            return true;
        } catch (java.io.IOException e) {
            Debug.error("DTEDFrame close(): File IO Error!\n" + e.toString());
            return false;
        }
    }

    /**
     * If the BinaryBufferedFile was closed, this method attempts to
     * reopen it.
     *
     * @return true if the opening was successful.
     */
    protected boolean reopen() {
        try {
            binFile = new BinaryBufferedFile(path);
            //          binFile = new BinaryFile(path);
            return true;
        } catch (FileNotFoundException e) {
            Debug.error("DTEDFrame reopen(): file " + path + " not found");
            return false;
        } catch (java.io.IOException e) {
            Debug.error("DTEDFrame close(): File IO Error!\n" + e.toString());
            return false;
        }
    }

    //////////////////
    // These functions can be called from the outside,
    // as queries about the data
    //////////////////

    /**
     * The elevation at the closest SW post to the given lat/lon. This
     * is just a go-to-the-closest-post solution.
     *
     * @param lat latitude in decimal degrees.
     * @param lon longitude in decimal degrees.
     * @return elevation at lat/lon in meters.
     */
    public int elevationAt(float lat, float lon) {
        if (frame_is_valid == true) {
            if (lat >= dsi.sw_lat && lat <= dsi.ne_lat && lon >= dsi.sw_lon
                    && lon <= dsi.ne_lon) {

                // lat/lon_post_intervals are *10 too big -
                // extra 0 in 36000 to counteract
                int lat_index = Math.round((lat - dsi.sw_lat) * 36000
                        / uhl.lat_post_interval);
                int lon_index = Math.round((lon - dsi.sw_lon) * 36000
                        / uhl.lon_post_interval);

                if (elevations[lon_index] == null)
                    read_data_record(lon_index);

                return (int) elevations[lon_index][lat_index];
            }
        }
        return -32767; // Considered a null elevation value
    }

    /**
     * Interpolated elevation at a given lat/lon - should be more
     * precise than elevationAt(), but that depends on the resolution
     * of the data.
     *
     * @param lat latitude in decimal degrees.
     * @param lon longitude in decimal degrees.
     * @return elevation at lat/lon in meters.
     */
    public int interpElevationAt(float lat, float lon) {
        if (frame_is_valid == true) {
            if (lat >= dsi.sw_lat && lat <= dsi.ne_lat && lon >= dsi.sw_lon
                    && lon <= dsi.ne_lon) {

                // lat/lon_post_intervals are *10 too big -
                // extra 0 in 36000 to counteract
                float lat_index = (lat - dsi.sw_lat) * 36000F
                        / uhl.lat_post_interval;
                float lon_index = (lon - dsi.sw_lon) * 36000F
                        / uhl.lon_post_interval;

                int lflon_index = (int) Math.floor(lon_index);
                int lclon_index = (int) Math.ceil(lon_index);
                /*int lflat_index = (int) Math.floor(lat_index);*/
                int lclat_index = (int) Math.ceil(lat_index);

                if (elevations[lflon_index] == null)
                    read_data_record(lflon_index);
                if (elevations[lclon_index] == null)
                    read_data_record(lclon_index);

                //////////////////////////////////////////////////////
                // Print out grid of 20x20 elevations with
                // the "asked for" point being in the middle
                //          System.out.println("***Elevation Map***");
                //          for(int l = lclat_index + 5; l > lflat_index - 5;
                // l--) {
                //              System.out.println();
                //              for(int k = lflon_index - 5; k < lclon_index + 5;
                // k++) {
                //                  if (elevations[k]==null) read_data_record(k);
                //                  System.out.print(elevations[k][l] + " ");
                //              }
                //          }
                //          System.out.println();System.out.println();
                //////////////////////////////////////////////////////

                int ul = elevations[lflon_index][lclat_index];
                int ur = elevations[lclon_index][lclat_index];
                int ll = elevations[lflon_index][lclat_index];
                int lr = elevations[lclon_index][lclat_index];

                float answer = resolve_four_points(ul,
                        ur,
                        lr,
                        ll,
                        lat_index,
                        lon_index);
                return Math.round(answer);
            }
        }
        return -32767; // Considered a null elevation value
    }

    /**
     * Return an index of ints representing the starting x, y and
     * ending x, y of elevation posts given a lat lon box. It does
     * check to make sure that the upper lat is larger than the lower,
     * and left lon is less than the right.
     *
     * @param ullat upper latitude in decimal degrees.
     * @param ullon left longitude in decimal degrees.
     * @param lrlat lower latitude in decimal degrees.
     * @param lrlon right longitude in decimal degrees.
     * @return int[4] array of start x, start y, end x, and end y.
     */
    public int[] getIndexesFromLatLons(float ullat, float ullon, float lrlat,
                                       float lrlon) {
        float upper = ullat;
        float lower = lrlat;
        float right = lrlon;
        float left = ullon;

        // Since matrix indexes depend on these being in the right
        // order, we'll double check and flip values, just to make
        // sure lower is lower, and higher is higher.
        if (ullon > lrlon) {
            right = ullon;
            left = lrlon;
        }

        if (lrlat > ullat) {
            upper = lrlat;
            lower = ullat;
        }

        int[] ret = new int[4];
        float ullat_index = (upper - dsi.sw_lat) * 36000F
                / uhl.lat_post_interval;
        float ullon_index = (left - dsi.sw_lon) * 36000F
                / uhl.lon_post_interval;
        float lrlat_index = (lower - dsi.sw_lat) * 36000F
                / uhl.lat_post_interval;
        float lrlon_index = (right - dsi.sw_lon) * 36000F
                / uhl.lon_post_interval;

        ret[0] = (int) Math.round(ullon_index);
        ret[1] = (int) Math.round(lrlat_index);
        ret[2] = (int) Math.round(lrlon_index);
        ret[3] = (int) Math.round(ullat_index);

        if (ret[0] < 0)
            ret[0] = 0;
        if (ret[0] > uhl.num_lon_lines - 2)
            ret[0] = uhl.num_lon_lines - 2;
        if (ret[1] < 0)
            ret[1] = 0;
        if (ret[1] > uhl.num_lat_points - 2)
            ret[1] = uhl.num_lat_points - 2;
        if (ret[2] < 0)
            ret[2] = 0;
        if (ret[2] > uhl.num_lon_lines - 2)
            ret[2] = uhl.num_lon_lines - 2;
        if (ret[3] < 0)
            ret[3] = 0;
        if (ret[3] > uhl.num_lat_points - 2)
            ret[3] = uhl.num_lat_points - 2;
        return ret;

    }

    /**
     * Return a two dimensional array of posts between lat lons.
     *
     * @param ullat upper latitude in decimal degrees.
     * @param ullon left longitude in decimal degrees.
     * @param lrlat lower latitude in decimal degrees.
     * @param lrlon right longitude in decimal degrees.
     * @return array of elevations in meters. The spacing of the posts
     *         depends on the DTED level.
     */
    public short[][] getElevations(float ullat, float ullon, float lrlat,
                                   float lrlon) {
        int[] indexes = getIndexesFromLatLons(ullat, ullon, lrlat, lrlon);
        return getElevations(indexes[0], indexes[1], indexes[2], indexes[3]);
    }

    /**
     * Return a two dimensional array of posts between lat lons.
     * Assumes that the indexes are checked to not exceed their bounds
     * as defined in the file. getIndexesFromLatLons() checks this.
     *
     * @param startx starting index (left) of the greater matrix to
     *        make the left side of the returned matrix.
     * @param starty starting index (lower) of the greater matrix to
     *        make the bottom side of the returned matrix.
     * @param endx ending index (right) of the greater matrix to make
     *        the left side of the returned matrix.
     * @param endy ending index (top) of the greater matrix to make
     *        the top side of the returned matrix.
     * @return array of elevations in meters. The spacing of the posts
     *         depends on the DTED level.
     */
    public short[][] getElevations(int startx, int starty, int endx, int endy) {
        int upper = endy;
        int lower = starty;
        int right = endx;
        int left = startx;

        // Since matrix indexes depend on these being in the right
        // order, we'll double check and flip values, just to make
        // sure lower is lower, and higher is higher.
        if (startx > endx) {
            right = startx;
            left = endx;
        }

        if (starty > endy) {
            upper = starty;
            lower = endy;
        }

        short[][] matrix = new short[right - left + 1][upper - lower + 1];
        int matrixColumn = 0;
        for (int x = left; x <= right; x++) {
            if (elevations[x] == null)
                read_data_record(x);
            System.arraycopy(elevations[x],
                    lower,
                    matrix[matrixColumn],
                    0,
                    (upper - lower + 1));
            matrixColumn++;
        }
        return matrix;
    }

    //////////////////
    // Internal methods
    //////////////////

    /**
     * A try at interoplating the corners of the surrounding posts,
     * given a lat lon. Called from a function where the data for the
     * lon has been read in.
     */
    private float resolve_four_points(int ul, int ur, int lr, int ll,
                                      float lat_index, float lon_index) {
        float top_avg = ((lon_index - new Double(Math.floor(lon_index)).floatValue()) * (float) (ur - ul))
                + ul;
        float bottom_avg = ((lon_index - new Double(Math.floor(lon_index)).floatValue()) * (float) (lr - ll))
                + ll;
        float right_avg = ((lat_index - new Double(Math.floor(lat_index)).floatValue()) * (float) (ur - lr))
                + lr;
        float left_avg = ((lat_index - new Double(Math.floor(lat_index)).floatValue()) * (float) (ul - ll))
                / 100.0F + ll;

        float lon_avg = ((lat_index - new Double(Math.floor(lat_index)).floatValue()) * (top_avg - bottom_avg))
                + bottom_avg;
        float lat_avg = ((lon_index - new Double(Math.floor(lon_index)).floatValue()) * (right_avg - left_avg))
                + left_avg;

        float result = (lon_avg + lat_avg) / 2.0F;
        return result;
    }

    /**
     * Reads one longitude line of posts. Assumes that the binFile is
     * valid.
     *
     * @return true if the column of data was successfully read
     */
    protected boolean read_data_record(int lon_index) {
        try {
            if (binFile == null)
                if (!reopen())
                    return false;

            // Set to beginning of file section, then skip to index
            // data
            // 12 = 1+3+2+2+4 = counts and checksum
            // 2*uhl....size of elevation post space
            binFile.seek(UHL_SIZE + DSI_SIZE + ACC_SIZE
                    + (lon_index * (12 + (2 * uhl.num_lat_points))));
            /*int sent = */binFile.read();
            binFile.skipBytes(3); // 3 byte data_block_count
            /*short lon_count = */binFile.readShort();
            /*short lat_count = */binFile.readShort();
            // Allocate the rows of the row
            elevations[lon_index] = new short[uhl.num_lat_points];
            for (int j = 0; j < uhl.num_lat_points; j++)
                elevations[lon_index][j] = binFile.readShortData();

        } catch (IOException e3) {
            Debug.error("DTEDFrame.RDR: Error reading file.");
            e3.printStackTrace();
            elevations[lon_index] = null;
            return false;
        } catch (FormatException f) {
            Debug.error("DTEDFrame.RDR: File IO Format error!");
            elevations[lon_index] = null;
            return false;
        }
        return true;
    }

    /**
     * Read all the elevation posts, at one time. Assumes that the
     * file is open and ready.
     *
     * @return true if the elevation columns were read.
     */
    protected boolean read_data_records() {
        boolean ret = true;
        for (int lon_index = 0; lon_index < uhl.num_lon_lines; lon_index++) {
            if (read_data_record(lon_index) == false)
                ret = false;
        }
        return ret;
    }

    /**
     * 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 OMRaster getOMRaster(EqualArc proj) {
        return getOMRaster(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 OMRaster getOMRaster(DTEDFrameSubframeInfo dfsi,
                                DTEDFrameColorTable colortable, EqualArc 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);
        }

        dfsi.xPixInterval = 360 / proj.getXPixConstant(); //degrees/pixel
        dfsi.yPixInterval = 90 / proj.getYPixConstant();
        dfsi.height = (int) (1 / dfsi.yPixInterval);
        dfsi.width = (int) (1 / dfsi.xPixInterval);

        // Will trigger the right thing in getSubframeOMRaster;
        subframes = null;

        return getSubframeOMRaster(dfsi, colortable);
    }

    /**
     * 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 OMRaster getSubframeOMRaster(DTEDFrameSubframeInfo dfsi,
                                        DTEDFrameColorTable colortable) {
        if (!frame_is_valid)
            return null;

        OMRaster 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 cordinates 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) {

            // The subframe section will not be null, because it is
            // created when the subframe is.
            if (subframe.image != null && subframe.si.equals(dfsi)) {
                // IF there is an image in the cache and the drawing
                // parameters are correct
                raster = subframe.image;

                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 (subframe.image == null) {
                if (Debug.debugging("dted")) {
                    Debug.output("   +++ DTEDFrame: creating subframe image");
                }
                if (dfsi.colorModel == OMRasterObject.COLORMODEL_DIRECT)
                    subframe.image = new OMRaster(lat_origin, lon_origin, dfsi.width, dfsi.height, new int[dfsi.height
                            * dfsi.width]);
                else
                    subframe.image = new OMRaster(lat_origin, lon_origin, dfsi.width, dfsi.height, null, colortable.colors, 255);
            }

            //  If there is an image, the types are different and it
            // needs to be
            //  redrawn
            subframe.si = dfsi.makeClone();

        } else {

            if (Debug.debugging("dted")) {
                Debug.output("   +++ DTEDFrame: creating subframe");
            }

            subframes[dfsi.subx][dfsi.suby] = new DTEDFrameSubframe(dfsi);
            subframe = subframes[dfsi.subx][dfsi.suby];
            if (dfsi.colorModel == OMRasterObject.COLORMODEL_DIRECT) {
                subframe.image = new OMRaster(lat_origin, lon_origin, dfsi.width, dfsi.height, new int[dfsi.height
                        * dfsi.width]);
            } else {
                subframe.image = new OMRaster(lat_origin, lon_origin, dfsi.width, dfsi.height, null, colortable.colors, 255);
            }
        }

        raster = subframe.image;

        // 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 = modifier / 10;

            for (int h = dfsi.slopeAdjust; h < 5; h++)
                modifier = modifier * 10;
            distance = Math.sqrt((modifier * lon_interval * lon_interval)
                    + (modifier * lat_interval * lat_interval));
        }
        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) && !read_data_record(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) && !read_data_record(xnw))
                        || ((elevations[xse] == null) && !read_data_record(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;
                            }
                        }
                    }
                    if (dfsi.colorModel == OMRasterObject.COLORMODEL_DIRECT)
                        raster.setPixel(x,
                                y,
                                colortable.colors[assignment].getRGB());
                    else
                        raster.setByte(x, y, (byte) 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;
                        if (dfsi.colorModel == OMRasterObject.COLORMODEL_DIRECT)
                            raster.setPixel(x,
                                    y,
                                    colortable.colors[assignment].getRGB());
                        else
                            raster.setByte(x, y, (byte) 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;
                        if (dfsi.colorModel == OMRasterObject.COLORMODEL_DIRECT)
                            raster.setPixel(x,
                                    y,
                                    colortable.colors[assignment].getRGB());
                        else
                            raster.setByte(x, y, (byte) 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;

                    if (dfsi.colorModel == OMRasterObject.COLORMODEL_DIRECT)
                        raster.setPixel(x, y, colortable.colors[c].getRGB());
                    else
                        raster.setByte(x, y, (byte) 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;

                    if (dfsi.colorModel == OMRasterObject.COLORMODEL_DIRECT)
                        raster.setPixel(x,
                                y,
                                colortable.colors[assignment].getRGB());
                    else
                        raster.setByte(x, y, (byte) assignment);
                }
            }
        }

        if (Debug.debugging("dteddetail"))
            Debug.output("DTEDFrame: leaving raster");
        return raster;

    }

    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]);
        DTEDFrame df = new DTEDFrame(args[0]);
        if (df.frame_is_valid) {
            System.out.println(df.uhl);
            System.out.println(df.dsi);

            //          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 com.bbn.openmap.LatLonPoint(lat, lon), 1500000, 600, 600);
        final OMRaster ras = df.getOMRaster(crg);

        // Pushes the image to the left top of the frame.
        crg.setHeight(ras.getHeight());
        crg.setWidth(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(ras.getWidth(), ras.getHeight());
        window.setVisible(true);
        window.repaint();
    }
}
TOP

Related Classes of com.bbn.openmap.layer.dted.DTEDFrame

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.