Subversion Repositories display

Rev

Rev 231 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2010.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */

package test.display;

import uk.me.parabola.imgfmt.app.ImgFileReader;

/**
 * Standalone program to display the DEM file.  This stores a
 * digital elevation model used to display shaded surface and profiles of tracks.
 *
 * @author Ronny Klier
 *
 */

public class DemDisplay extends CommonDisplay {

        private class DemTile {
                private DemSection section;
                private int tileNumberLat;
                private int tileNumberLon;
                private int offset;                     // offset from section.dataOffset2
                private int dataLength;                 // number of bytes for compressed elevation data
                private short baseHeight;               // base or minimum height in this tile
                private short differenceHeight; // maximum height above baseHeight (elevation?)
               
                DemTile(DemSection parent, int numLat, int numLon) {
                        section = parent;
                        tileNumberLat = numLat;
                        tileNumberLon = numLon;
                }
               
                void readHeader(ImgFileReader reader, int baseOffset) {
                        Displayer d = new Displayer(reader);
                        d.setTitle("DEM Tile Header");
                        DisplayItem item = d.item();
                        item.addText("Tile row %1$s column %2$s", tileNumberLat, tileNumberLon);
                       
                        reader.position(section.dataOffset + (section.tilesLon * tileNumberLat + tileNumberLon) * section.tileDescSize);
                       
                        switch (section.offsetSize) {
                        case 1:
                                offset = d.byteValue("offset in data section");
                                break;
                        case 2:
                                offset = d.shortValue("offset in data section");
                                break;
                        case 3:
                                offset = d.int3Value("offset in data section");
                                break;
                        }
                        offset += baseOffset;
                        if (1 == section.baseSize) {
                                baseHeight = d.byteValue("minimum height");
                        } else {
                                baseHeight = d.shortValue("minimum height");
                        }
                        if (1 == section.differenceSize) {
                                differenceHeight = d.byteValue("elevation");
                        } else {
                                differenceHeight = d.shortValue("elevation");
                        }
                        d.print(outStream);
                }
               
                void setDataLength(int nextOffset) {
                        dataLength = nextOffset - offset;
                        if (dataLength < 0)
                                dataLength = 0;
                }

                public void printRawData(ImgFileReader reader) {
                        reader.position(offset);
                        Displayer d = new Displayer(reader);
                        d.setTitle(String.format("Raw data for tile row %1$s column %2$s", tileNumberLat, tileNumberLon));
                       
                        d.rawValue(dataLength, "real DEM data");
                        d.print(outStream);
                }
        }
       
        private class DemSection {
                private int num;
                private int pointsPerLat;
                private int pointsPerLon;
                private int tilesLat;
                private int tilesLon;
                private byte offsetSize;
                private byte baseSize;
                private byte differenceSize;
                private short tileDescSize;
                private int dataOffset;
                private int dataOffset2;
                private int pointsDistanceLat;
                private int pointsDistanceLon;
                private int top;
                private int left;
               
                private DemTile[] tiles;
               
                protected void print(ImgFileReader reader) {
                        readHeader(reader);
                }
               
                private void readHeader(ImgFileReader reader) {
                        Displayer d = new Displayer(reader);
                        d.setTitle("DEM Sector Header");
                        num = d.shortValue("#");                        //0x00 - 0x01
                        pointsPerLat = d.intValue("Points per tile (latitude");         //0x02 - 0x05
                        pointsPerLon = d.intValue("Points per tile (longitude)");//0x06 - 0x09
                        d.intValue("unknown integer1");         //0x0a - 0x0d
                        d.intValue("unknown integer2");         //0x0e - 0x11
                        d.shortValue("unknown short");          //0x12 - 0x13
                        tilesLon = d.intValue("Tiles per longitude") + 1;               //0x14 - 0x17
                        tilesLat = d.intValue("Tiles per latitude") + 1;                //0x18 - 0x1B
                       
                        short recordDesc = d.shortValue("Flags for tile description");          //0x1C - 0x1D
                        DisplayItem item = d.item();
                        offsetSize = (byte)((recordDesc & 3) + 1);
                        baseSize = (byte)(((recordDesc & 4) >> 2) + 1);
                    differenceSize = (byte)(((recordDesc & 8) >> 3) + 1);
                        item.addText("Data offset has %s bytes", offsetSize);
                        item.addText("Base height has %s bytes", baseSize);
                        item.addText("Height difference has %s bytes", differenceSize);
                        tileDescSize = d.shortValue("Size of tile description");//0x1E - 0x1F
                       
                        dataOffset = d.intValue("offset of first tile description");// 0x20 - 0x23
                        dataOffset2 = d.intValue("offset of first tiles data");         //0x24 - 0x27
                        left = d.intValue("western bound");             //0x28-0x2B
                        top = d.intValue("northern bound"); //0x2C - 0x2F
                        d.item().addText("In degrees lat,lon: %.4f,%.4f",
                                        DemDisplay.toDegrees(top),
                                        DemDisplay.toDegrees(left));

                        pointsDistanceLat = d.intValue("map units between points (latitude)");          //0x30 - 0x33
                        pointsDistanceLon = d.intValue("map units between points (longitude)");         //0x34 - 0x37
                        d.shortValue("minimum height");         //0x38 - 0x39
                        d.shortValue("maximum height");         //0x3A - 0x3B

                        d.print(outStream);
                       
                        tiles = new DemTile[tilesLat * tilesLon];
                       
                        // now read the tile description
                        for (int i = 0; i < tiles.length; ++i) {
                                tiles[i] = new DemTile(this, i / tilesLon, i % tilesLon);
                                tiles[i].readHeader(reader, dataOffset2);
                                if (i != 0) {
                                        tiles[i-1].setDataLength(tiles[i].offset);
                                }
                                // data length of last tile has to be set after reading next section
                        }
                }
               
                private void setLastDataLength(int nextSectionOffset) {
                        tiles[tiles.length -1].setDataLength(nextSectionOffset);
                }

                public void printRawData(ImgFileReader reader) {
                        Displayer d = new Displayer(reader);
                        d.setTitle(String.format("Printing raw data of sector %s", num));
                       
                        for (int i = 0; i < tiles.length; ++i) {
                                tiles[i].printRawData(reader);
                        }                      
                        d.print(outStream);
                }
        }
       
        private DemSection[] sections;
        private int sectionOffset;
        private short sectionSize;
        private boolean useMeters;
       
        @Override
        protected void print() {
                readCommonHeader();
                readFileHeader();
        }
       
        private void readFileHeader() {
                Displayer d = new Displayer(reader);
                d.setTitle("DEM Header");

                useMeters = 1 != (d.intValue("Flags ?") & 1);
                DisplayItem item = d.item();
                if (useMeters) {
                        item.addText("elevation is given in meters");
                } else {
                        item.addText("elevation is given in feet");
                }
                sections = new DemSection[d.shortValue("Number of zoom levels/sectors")];
               
                d.intValue("unknown integer");
                sectionSize = d.shortValue("size of sector headers");
                sectionOffset = d.intValue("offset of first sector header");
               
                if (getHeaderLen() > 0x25) {
                        d.intValue("unknown integer at 0x25");
                }
               
                d.print(outStream);
               
                reader.position(sectionOffset);
                for (int i = 0; i < sections.length; i++) {
                        reader.position(sectionOffset + sectionSize * i);
                        sections[i] = new DemSection();
                        sections[i].print(reader);
                        if (i != 0) {
                                // data of last tile of previous section ends before first tile of this section
                                sections[i-1].setLastDataLength(sections[i].dataOffset2);
                        }
                        if (i - 1 == sections.length) {
                                // data of last tile of last section ends before begin of section description
                                sections[i].setLastDataLength(sectionOffset);
                        }
                }
                // now iterate a second time over section and tiles and print out raw data
                for (int i = 0; i < sections.length; ++i) {
                        sections[i].printRawData(reader);
                }
        }

        private static double toDegrees(int val) {
                return (double) val * (360.0 / 4294967296.0);
        }
       
       
        public static void main(String[] args) {
                if (args.length < 1) {
                        System.err.println("Usage: demdisplay <filename>");
                        System.exit(1);
                }

                CommonDisplay td = new DemDisplay();
                td.display(args[0],"DEM");
        }
}