This patch enables the display tool to read the known parts of DEM subfiles. Please refer to http://wiki.openstreetmap.org/wiki/OSM_Map_On_Garmin/DEM_Subfile_Format for a description.

Notes:
- Using the discovered parts it is possible to read the coordinates of the covered areas, their minimum and maximum heights and the data which builds the real elevation model. - The encryption of this data is still unknown. IMHO it is normalized (using the difference between minimum and maximum height and perhaps an additional field) and compressed. But I'm not an expert on data encrytion ;-)
Index: src/test/display/CommonDisplay.java
===================================================================
--- src/test/display/CommonDisplay.java	(revision 229)
+++ src/test/display/CommonDisplay.java	(working copy)
@@ -143,7 +143,7 @@
 	 * @param name The name of the .img file.
 	 * @param fileExt The file to get.  It is found by extension.
 	 */
-	protected void display(String name, String fileExt) {
+	public void display(String name, String fileExt) {
 		if (name.endsWith(fileExt)) {
 			display(name);
 			return;
Index: src/test/display/DemDisplay.java
===================================================================
--- src/test/display/DemDisplay.java	(revision 0)
+++ src/test/display/DemDisplay.java	(revision 0)
@@ -0,0 +1,247 @@
+/*
+ * 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 or
+ * version 2 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.Utils;
+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");
+	}
+}
Index: src/test/display/RgnDisplay.java
===================================================================
--- src/test/display/RgnDisplay.java	(revision 229)
+++ src/test/display/RgnDisplay.java	(working copy)
@@ -342,6 +342,7 @@
 
 		} catch (FileNotFoundException e) {
 			System.err.println("Could not open TRE file");
+			return;
 		}
 
 		TREHeader header = (TREHeader) tre.getHeader();
Index: src/test/display/Section.java
===================================================================
--- src/test/display/Section.java	(revision 229)
+++ src/test/display/Section.java	(working copy)
@@ -78,7 +78,7 @@
 	 * Number of items. Only valid when there is a recsize set.
 	 */
 	public int getNumberOfRecords() {
-		return len/ recordSize;
+		return (len == 0) ? 0 : len/ recordSize;
 	}
 
 	public int getMagic() {
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to