v2

Space optimisation - no longer outputs per-subdivision 13-byte record if
the map contains no elements that have an extended type.

-------------------

Ahoy there shipmates,

This patch is a first stab at providing support for the 3-byte extended
types that are used on marine maps.

Extended types are specified as a 6 digit hex number. The first two
digits are always 01. An example type is 0x010200 (point type Buoy).

Points, lines and polygons can all be given extended types.

The cGPSMapper user manual lists all of the types.

Note that routable ways cannot have an extended type. If you try to
give a road an extended type, it will converted into a line.

At this time, the various extra attributes that can be assigned to the
marine entities (depth, colour, light colour/flash, etc.) are not
handled but I have made some progress in understanding their encoding
so at least some of these could be supported in the future. Obviously,
the OSM data would need to be enriched to specify the required
attributes.

It now works well enough to warrant testing on more map data but I
am expecting that there will be problems given the extent of the patch
and the nature of what it's doing.

Please test if you can and report success/failure/etc.

Cheers,

Mark


diff --git a/src/uk/me/parabola/imgfmt/app/trergn/LinePreparer.java b/src/uk/me/parabola/imgfmt/app/trergn/LinePreparer.java
index c99e807..eb5d520 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/LinePreparer.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/LinePreparer.java
@@ -32,6 +32,7 @@ class LinePreparer {
 	private final Polyline polyline;
 
 	private boolean extraBit;
+	private boolean extTypeLine;
 	private boolean xSameSign;
 	private boolean xSignNegative;     // Set if all negative
 
@@ -55,6 +56,8 @@ class LinePreparer {
 			extraBit = true;
 		}
 
+		extTypeLine = line.hasExtendedType();
+
 		polyline = line;
 		calcLatLong();
 		calcDeltas();
@@ -105,6 +108,10 @@ class LinePreparer {
 			log.debug("y same is", ySameSign, "sign is", ySignNegative);
 		}
 
+		if(extTypeLine) {
+			bw.put1(false);		// no extra bits required
+		}
+
 		// first extra bit always appears to be false
 		// refers to the start point?
 		if (extraBit)
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/MapObject.java b/src/uk/me/parabola/imgfmt/app/trergn/MapObject.java
index 9a3c017..07933cd 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/MapObject.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/MapObject.java
@@ -19,9 +19,14 @@ package uk.me.parabola.imgfmt.app.trergn;
 import uk.me.parabola.imgfmt.app.Label;
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
 
+import uk.me.parabola.mkgmap.general.MapElement;
+
 import java.util.ArrayList;
 import java.util.List;
 
+import java.io.OutputStream;
+import java.io.IOException;
+
 /**
  * An object that appears in a map.  One of point, polyline, polygon or indexed
  * point.
@@ -57,6 +62,8 @@ public abstract class MapObject {
 	 */
 	public abstract void write(ImgFileWriter file);
 
+	public abstract void write(OutputStream stream) throws IOException;
+
 	int getDeltaLat() {
 		return deltaLat;
 	}
@@ -83,6 +90,10 @@ public abstract class MapObject {
 		this.type = type;
 	}
 
+	public boolean hasExtendedType() {
+		return MapElement.hasExtendedType(type);
+	}
+
 	/** 
 	 * Set an ordinary unshifted latitude.  It will be calculated
 	 * relative to the subdivision. 
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Overview.java b/src/uk/me/parabola/imgfmt/app/trergn/Overview.java
index 2f164b5..29f949d 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/Overview.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/Overview.java
@@ -33,6 +33,7 @@ public abstract class Overview implements Comparable<Overview> {
 	public static final int SHAPE_KIND = 3;
 
 	private final int kind; // The kind of overview; point, line etc.
+	private final char extType;
 	private final char type;
 	private final char subType;
 	private final int minResolution;
@@ -43,6 +44,7 @@ public abstract class Overview implements Comparable<Overview> {
 	protected Overview(int kind, int fullType, int minres) {
 		this.kind = kind;
 
+		this.extType = (char)((fullType >> 16) & 0xff);
 		this.type = (char) (fullType >> 8 & 0xff);
 		this.subType = (char) (fullType & 0xff);
 		this.minResolution = minres;
@@ -54,10 +56,18 @@ public abstract class Overview implements Comparable<Overview> {
 	}
 
 	public void write(ImgFileWriter file) {
-		file.put((byte) (type & 0xff));
-		file.put((byte) maxLevel);
-		if (size > 2)
-			file.put((byte) (subType & 0xff));
+		if(extType != 0) {
+			file.put((byte)type);
+			file.put((byte)maxLevel);
+			file.put((byte)subType);
+			file.put((byte)0);
+		}
+		else {
+			file.put((byte) (type & 0xff));
+			file.put((byte) maxLevel);
+			if (size > 2)
+				file.put((byte) (subType & 0xff));
+		}
 	}
 
 	/**
@@ -83,7 +93,10 @@ public abstract class Overview implements Comparable<Overview> {
 			return false;
 
 		Overview ov = (Overview) obj;
-		return ov.kind == kind && ov.type == type && ov.subType == subType;
+		return (ov.kind == kind &&
+				ov.extType == extType &&
+				ov.type == type &&
+				ov.subType == subType);
 	}
 
 	public int getKind() {
@@ -106,6 +119,10 @@ public abstract class Overview implements Comparable<Overview> {
 			return kind > ov.kind ? 1 : -1;
 		}
 
+		if(extType != ov.extType) {
+			return extType - ov.extType;
+		}
+
 		int res;
 		if (type == ov.type) {
 			if (subType == ov.subType)
@@ -132,4 +149,8 @@ public abstract class Overview implements Comparable<Overview> {
 	public int getMinResolution() {
 		return minResolution;
 	}
+
+	public boolean hasExtType() {
+		return extType != 0;
+	}
 }
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Point.java b/src/uk/me/parabola/imgfmt/app/trergn/Point.java
index 4ec3d6e..84b6434 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/Point.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/Point.java
@@ -19,6 +19,9 @@ package uk.me.parabola.imgfmt.app.trergn;
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
 import uk.me.parabola.imgfmt.app.lbl.POIRecord;
 
+import java.io.OutputStream;
+import java.io.IOException;
+
 /**
  * Represents a particular point object on a map.  A point has a type (town
  * restaurant etc) and a location as well as a name.
@@ -71,6 +74,40 @@ public class Point extends MapObject {
 			file.put(subtype);
 	}
 
+	/*
+	 * write the point to an OutputStream - only use for outputting
+	 * points with extended (3 byte) types.
+	 *
+	 */
+	public void write(OutputStream stream) throws IOException {
+		assert hasExtendedType();
+		int type = getType();
+		int labelOff = getLabel().getOffset();
+
+		if (poi != null) {
+			labelOff = poi.getOffset();
+			labelOff |= 0x400000;
+		}
+		if(labelOff != 0)
+			type |= 0x20;		// has label
+
+		stream.write(type >> 8);
+		stream.write(type);
+		int deltaLong = getDeltaLong();
+		int deltaLat = getDeltaLat();
+		stream.write(deltaLong);
+		stream.write(deltaLong >> 8);
+		stream.write(deltaLat);
+		stream.write(deltaLat >> 8);
+
+		if(labelOff != 0) {
+			stream.write(labelOff);
+			stream.write(labelOff >> 8);
+			stream.write(labelOff >> 16);
+		}
+		// FIXME - extra bytes?
+	}
+
 	public void setPOIRecord(POIRecord poirecord) {
 		this.poi = poirecord;
 	}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Polyline.java b/src/uk/me/parabola/imgfmt/app/trergn/Polyline.java
index f0b0bd5..64d7faa 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/Polyline.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/Polyline.java
@@ -19,6 +19,9 @@ package uk.me.parabola.imgfmt.app.trergn;
 import java.util.ArrayList;
 import java.util.List;
 
+import java.io.OutputStream;
+import java.io.IOException;
+
 import uk.me.parabola.imgfmt.app.BitWriter;
 import uk.me.parabola.imgfmt.app.Coord;
 import uk.me.parabola.imgfmt.app.ImgFileWriter;
@@ -135,6 +138,53 @@ public class Polyline extends MapObject {
 		file.put(bw.getBytes(), 0, blen+1);
 	}
 
+	/*
+	 * write the polyline to an OutputStream - only use for outputting
+	 * lines with extended (3 byte) types.
+	 *
+	 */
+	public void write(OutputStream stream) throws IOException {
+		assert hasExtendedType();
+		int type = getType();
+		int labelOff = getLabel().getOffset();
+
+		if(labelOff != 0)
+			type |= 0x20;		// has label
+		stream.write(type >> 8);
+		stream.write(type);
+
+		// need to prepare line info before outputing lat/lon
+		LinePreparer w = new LinePreparer(this);
+		BitWriter bw = w.makeBitStream();
+		int blen = bw.getLength();
+		assert blen > 1 : "zero length bitstream";
+		assert blen < 0x10000 : "bitstream too long " + blen;
+
+		int deltaLong = getDeltaLong();
+		int deltaLat = getDeltaLat();
+		stream.write(deltaLong);
+		stream.write(deltaLong >> 8);
+		stream.write(deltaLat);
+		stream.write(deltaLat >> 8);
+
+		if (blen >= 0x7f) {
+			stream.write((blen << 2) | 2);
+			stream.write((blen << 2) >> 8);
+		}
+		else {
+			stream.write((blen << 1) | 1);
+		}
+
+		stream.write(bw.getBytes(), 0, blen);
+
+		if(labelOff != 0) {
+			stream.write(labelOff);
+			stream.write(labelOff >> 8);
+			stream.write(labelOff >> 16);
+		}
+		// FIXME - extra bytes?
+	}
+
 	public void addCoord(Coord co) {
 		points.add(co);
 	}
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/RGNFile.java b/src/uk/me/parabola/imgfmt/app/trergn/RGNFile.java
index 5f96680..f0300e8 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/RGNFile.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/RGNFile.java
@@ -22,6 +22,9 @@ import uk.me.parabola.imgfmt.app.ImgFileWriter;
 import uk.me.parabola.imgfmt.fs.ImgChannel;
 import uk.me.parabola.log.Logger;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
 /**
  * The region file.  Holds actual details of points and lines etc.
  *
@@ -47,6 +50,9 @@ public class RGNFile extends ImgFile {
 	private int indPointPtrOff;
 	private int polylinePtrOff;
 	private int polygonPtrOff;
+	private ByteArrayOutputStream extTypePointsData;
+	private ByteArrayOutputStream extTypeLinesData;
+	private ByteArrayOutputStream extTypeAreasData;
 
 	public RGNFile(ImgChannel chan) {
 		setHeader(header);
@@ -63,6 +69,19 @@ public class RGNFile extends ImgFile {
 
 		header.setDataSize(position() - HEADER_LEN);
 
+		if(extTypeAreasData != null) {
+			header.setExtTypeAreasInfo(position(), extTypeAreasData.size());
+			getWriter().put(extTypeAreasData.toByteArray());
+		}
+		if(extTypeLinesData != null) {
+			header.setExtTypeLinesInfo(position(), extTypeLinesData.size());
+			getWriter().put(extTypeLinesData.toByteArray());
+		}
+		if(extTypePointsData != null) {
+			header.setExtTypePointsInfo(position(), extTypePointsData.size());
+			getWriter().put(extTypePointsData.toByteArray());
+		}
+
 		getHeader().writeHeader(getWriter());
 	}
 
@@ -93,7 +112,33 @@ public class RGNFile extends ImgFile {
 	}
 
 	public void addMapObject(MapObject item) {
-		item.write(getWriter());
+		if(item.hasExtendedType()) {
+			try {
+				if(item instanceof Point) {
+					if(extTypePointsData == null)
+						extTypePointsData = new ByteArrayOutputStream();
+					item.write(extTypePointsData);
+				}
+				else if(item instanceof Polygon) {
+					if(extTypeAreasData == null)
+						extTypeAreasData = new ByteArrayOutputStream();
+					item.write(extTypeAreasData);
+				}
+				else if(item instanceof Polyline) {
+					if(extTypeLinesData == null)
+						extTypeLinesData = new ByteArrayOutputStream();
+					item.write(extTypeLinesData);
+				}
+				else
+					log.error("Can't add object of type " + item.getClass());
+			}
+			catch (IOException ioe) {
+				log.error("Error writing extended type object: " + ioe.getMessage());
+			}
+		}
+		else {
+			item.write(getWriter());
+		}
 	}
 
 	public void setIndPointPtr() {
@@ -144,4 +189,22 @@ public class RGNFile extends ImgFile {
 	public ImgFileWriter getWriter() {
 		return super.getWriter();
 	}
+
+	public int getExtTypePointsSize() {
+		return (extTypePointsData == null)? 0 : extTypePointsData.size();
+	}
+
+	public int getExtTypeLinesSize() {
+		return (extTypeLinesData == null)? 0 : extTypeLinesData.size();
+	}
+
+	public int getExtTypeAreasSize() {
+		return (extTypeAreasData == null)? 0 : extTypeAreasData.size();
+	}
+
+	public boolean haveExtendedTypes() {
+		return (extTypePointsData != null ||
+				extTypeLinesData != null ||
+				extTypeAreasData != null);
+	}
 }
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/RGNHeader.java b/src/uk/me/parabola/imgfmt/app/trergn/RGNHeader.java
index 55ed7e0..ded6152 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/RGNHeader.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/RGNHeader.java
@@ -28,16 +28,19 @@ import uk.me.parabola.imgfmt.app.Section;
  * @author Steve Ratcliffe
  */
 public class RGNHeader extends CommonHeader {
-	private static final int DEF_LEN = 29;
-	//private static final int DEF_LEN = 125;
+	//private static final int DEF_LEN = 29;
+	private static final int DEF_LEN = 125;
 	public static final int HEADER_LEN = DEF_LEN;
 
 	private int dataOffset;
 	private int dataSize;
 	
-	private final Section rgn2 = new Section();
-	private final Section rgn3 = new Section(rgn2);
-	private final Section rgn4 = new Section(rgn3);
+	private int extTypeAreasOffset;
+	private int extTypeAreasSize;
+	private int extTypeLinesOffset;
+	private int extTypeLinesSize;
+	private int extTypePointsOffset;
+	private int extTypePointsSize;
 
 	public RGNHeader() {
 		super(HEADER_LEN, "GARMIN RGN");
@@ -66,21 +69,24 @@ public class RGNHeader extends CommonHeader {
 		writer.putInt(dataOffset);
         writer.putInt(getDataSize());
 		if (getHeaderLength() > 29) {
-			rgn2.setPosition(dataOffset + dataSize);
-			rgn2.writeSectionInfo(writer);
+			writer.putInt(extTypeAreasOffset);
+			writer.putInt(extTypeAreasSize);
 			writer.putInt(0);
 			writer.putInt(0);
 			writer.putInt(0);
 			writer.putInt(0);
 			writer.putInt(0);
-			rgn3.writeSectionInfo(writer);
+
+			writer.putInt(extTypeLinesOffset);
+			writer.putInt(extTypeLinesSize);
 			writer.putInt(0);
 			writer.putInt(0);
 			writer.putInt(0);
 			writer.putInt(0);
 			writer.putInt(0);
 
-			rgn4.writeSectionInfo(writer);
+			writer.putInt(extTypePointsOffset);
+			writer.putInt(extTypePointsSize);
 			writer.putInt(0);
 			writer.putInt(0);
 			writer.putInt(0);
@@ -99,4 +105,19 @@ public class RGNHeader extends CommonHeader {
 	public void setDataSize(int dataSize) {
 		this.dataSize = dataSize;
 	}
+
+	public void setExtTypeAreasInfo(int offset, int size) {
+		extTypeAreasOffset = offset;
+		extTypeAreasSize = size;
+	}
+
+	public void setExtTypeLinesInfo(int offset, int size) {
+		extTypeLinesOffset = offset;
+		extTypeLinesSize = size;
+	}
+
+	public void setExtTypePointsInfo(int offset, int size) {
+		extTypePointsOffset = offset;
+		extTypePointsSize = size;
+	}
 }
\ No newline at end of file
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java b/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java
index 8446838..4da8f93 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/Subdivision.java
@@ -80,6 +80,13 @@ public class Subdivision {
 
 	private final List<Subdivision> divisions = new ArrayList<Subdivision>();
 
+	private int extTypeAreasOffset;
+	private int extTypeLinesOffset;
+	private int extTypePointsOffset;
+	private int extTypeAreasSize;
+	private int extTypeLinesSize;
+	private int extTypePointsSize;
+
 	/**
 	 * Subdivisions can not be created directly, use either the
 	 * {...@link #topLevelSubdivision} or {...@link #createSubdivision} factory
@@ -210,7 +217,7 @@ public class Subdivision {
 	}
 
 	public Point createPoint(String name) {
-		assert hasPoints || hasIndPoints;
+		//		assert hasPoints || hasIndPoints;
 		
 		Point p = new Point(this);
 		Label label = lblFile.newLabel(name);
@@ -220,7 +227,7 @@ public class Subdivision {
 	}
 
 	public Polyline createLine(String name, String ref) {
-		assert hasPolylines;
+		//		assert hasPolylines;
 		Label label = lblFile.newLabel(name);
 		Polyline pl = new Polyline(this);
 
@@ -236,13 +243,15 @@ public class Subdivision {
 			}
 		}
 
-		numPolylines++;
-		pl.setNumber(numPolylines);
 		return pl;
 	}
 
+	public void setPolylineNumber(Polyline pl) {
+		pl.setNumber(++numPolylines);
+	}
+
 	public Polygon createPolygon(String name) {
-		assert hasPolygons;
+		// assert hasPolygons;
 		Label label = lblFile.newLabel(name);
 		Polygon pg = new Polygon(this);
 
@@ -352,6 +361,36 @@ public class Subdivision {
 
 	public void startDivision() {
 		rgnFile.startDivision(this);
+		extTypeAreasOffset = rgnFile.getExtTypeAreasSize();
+		extTypeLinesOffset = rgnFile.getExtTypeLinesSize();
+		extTypePointsOffset = rgnFile.getExtTypePointsSize();
+	}
+
+	public void endDivision() {
+		extTypeAreasSize = rgnFile.getExtTypeAreasSize() - extTypeAreasOffset;
+		extTypeLinesSize = rgnFile.getExtTypeLinesSize() - extTypeLinesOffset;
+		extTypePointsSize = rgnFile.getExtTypePointsSize() - extTypePointsOffset;
+	}
+
+	public void writeExtTypeOffsetsRecord(ImgFileWriter file) {
+		file.putInt(extTypeAreasOffset);
+		file.putInt(extTypeLinesOffset);
+		file.putInt(extTypePointsOffset);
+		int kinds = 0;
+		if(extTypeAreasSize != 0)
+			++kinds;
+		if(extTypeLinesSize != 0)
+			++kinds;
+		if(extTypePointsSize != 0)
+			++kinds;
+		file.put((byte)kinds);
+	}
+
+	public void writeLastExtTypeOffsetsRecord(ImgFileWriter file) {
+		file.putInt(rgnFile.getExtTypeAreasSize());
+		file.putInt(rgnFile.getExtTypeLinesSize());
+		file.putInt(rgnFile.getExtTypePointsSize());
+		file.put((byte)0);
 	}
 
 	/**
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/TREFile.java b/src/uk/me/parabola/imgfmt/app/trergn/TREFile.java
index 6456cb9..35ff405 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/TREFile.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/TREFile.java
@@ -133,7 +133,7 @@ public class TREFile extends ImgFile implements Configurable {
 	 * the header needs to be written after the body (or obviously we could
 	 * make two passes).
 	 */
-	private void writeBody() {
+	private void writeBody(boolean includeExtendedTypeData) {
 		writeMapLevels();
 
 		writeSubdivs();
@@ -141,16 +141,10 @@ public class TREFile extends ImgFile implements Configurable {
 		writeCopyrights();
 
 		writeOverviews();
-	}
-
-	private void writeTre7() {
-		header.setTre7Pos(position());
-		byte[] tre7buf = new byte[13];
-		Arrays.fill(tre7buf, (byte) 0);
-		for (int i = 0; i < 4; i++) {
 
-			getWriter().put(tre7buf);
-			header.incTre7();
+		if(includeExtendedTypeData) {
+			writeExtTypeOffsetsRecords();
+			writeExtTypeOverviews();
 		}
 	}
 
@@ -198,6 +192,27 @@ public class TREFile extends ImgFile implements Configurable {
 		header.setSubdivSize(header.getSubdivSize() + 4);
 	}
 
+	private void writeExtTypeOffsetsRecords() {
+		header.setExtTypeOffsetsPos(position());
+		Subdivision sd = null;
+		for (int i = 15; i >= 0; i--) {
+			Zoom z = mapLevels[i];
+			if (z == null)
+				continue;
+
+			Iterator<Subdivision> it = z.subdivIterator();
+			while (it.hasNext()) {
+				sd = it.next();
+				sd.writeExtTypeOffsetsRecord(getWriter());
+				header.incExtTypeOffsetsSize();
+			}
+		}
+		if(sd != null) {
+			sd.writeLastExtTypeOffsetsRecord(getWriter());
+			header.incExtTypeOffsetsSize();
+		}
+	}
+
 	/**
 	 * Write out the map levels.  This is a mapping between the level number
 	 * and the resolution.
@@ -226,27 +241,67 @@ public class TREFile extends ImgFile implements Configurable {
 		// Point overview section
 		Collections.sort(pointOverviews);
 		for (Overview ov : pointOverviews) {
-			ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
-			ov.write(getWriter());
-			header.incPointSize();
+			if(!ov.hasExtType()) {
+				ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
+				ov.write(getWriter());
+				header.incPointSize();
+			}
 		}
 
 		// Line overview section.
 		header.setPolylinePos(position());
 		Collections.sort(polylineOverviews);
 		for (Overview ov : polylineOverviews) {
-			ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
-			ov.write(getWriter());
-			header.incPolylineSize();
+			if(!ov.hasExtType()) {
+				ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
+				ov.write(getWriter());
+				header.incPolylineSize();
+			}
 		}
 
 		// Polygon overview section
 		header.setPolygonPos(position());
 		Collections.sort(polygonOverviews);
 		for (Overview ov : polygonOverviews) {
-			ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
-			ov.write(getWriter());
-			header.incPolygonSize();
+			if(!ov.hasExtType()) {
+				ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
+				ov.write(getWriter());
+				header.incPolygonSize();
+			}
+		}
+	}
+
+	private void writeExtTypeOverviews() {
+
+		header.setExtTypeOverviewsPos(position());
+
+		// assumes overviews are already sorted
+
+		for (Overview ov : polylineOverviews) {
+			if(ov.hasExtType()) {
+				ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
+				ov.write(getWriter());
+				header.incExtTypeOverviewsSize();
+				header.incNumExtTypeLineTypes();
+			}
+		}
+
+		for (Overview ov : polygonOverviews) {
+			if(ov.hasExtType()) {
+				ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
+				ov.write(getWriter());
+				header.incExtTypeOverviewsSize();
+				header.incNumExtTypeAreaTypes();
+			}
+		}
+
+		for (Overview ov : pointOverviews) {
+			if(ov.hasExtType()) {
+				ov.setMaxLevel(decodeLevel(ov.getMinResolution()));
+				ov.write(getWriter());
+				header.incExtTypeOverviewsSize();
+				header.incNumExtTypePointTypes();
+			}
 		}
 	}
 
@@ -296,9 +351,9 @@ public class TREFile extends ImgFile implements Configurable {
 		TREFile.this.lastRgnPos = lastRgnPos;
 	}
 
-	public void write() {
+	public void write(boolean includeExtendedTypeData) {
 		// Do anything that is in structures and that needs to be dealt with.
-		writeBody();
+		writeBody(includeExtendedTypeData);
 	}
 
 	public void writePost() {
diff --git a/src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java b/src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java
index cc2c2de..53ad1d7 100644
--- a/src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java
+++ b/src/uk/me/parabola/imgfmt/app/trergn/TREHeader.java
@@ -50,6 +50,7 @@ public class TREHeader extends CommonHeader {
 	private static final char POLYGON_REC_LEN = 2;
 	private static final char POINT_REC_LEN = 3;
 	private static final char COPYRIGHT_REC_SIZE = 0x3;
+	private static final char EXT_TYPE_OFFSETS_REC_LEN = 13;
 	static final int SUBDIV_REC_SIZE = 14;
 	static final int SUBDIV_REC_SIZE2 = 16;
 
@@ -74,9 +75,12 @@ public class TREHeader extends CommonHeader {
 	private final Section polyline = new Section(POLYLINE_REC_LEN);
 	private final Section polygon = new Section(POLYGON_REC_LEN);
 	private final Section points = new Section(POINT_REC_LEN);
-	private final Section tre7 = new Section(points, (char) 13);
-	private final Section tre8 = new Section(tre7, (char) 4);
-	//private Section tre9 = new Section(tre8);
+	private final Section extTypeOffsets = new Section(points, EXT_TYPE_OFFSETS_REC_LEN);
+	private final Section extTypeOverviews = new Section(extTypeOffsets, (char) 4);
+
+	private int numExtTypeAreaTypes;
+	private int numExtTypeLineTypes;
+	private int numExtTypePointTypes;
 
 	private int mapId;
 
@@ -186,12 +190,13 @@ public class TREHeader extends CommonHeader {
 		if (getHeaderLength() > 120) {
 			writer.putInt(0);
 
-			tre7.writeSectionInfo(writer);
-			writer.putInt(0); // not usually zero
+			extTypeOffsets.writeSectionInfo(writer);
+			writer.putInt(0x0607);	// FIXME - guessed (could also be 0x487?)
 
-			tre8.writeSectionInfo(writer);
-			writer.putChar((char) 0);
-			writer.putInt(0);
+			extTypeOverviews.writeSectionInfo(writer);
+			writer.putChar((char)numExtTypeLineTypes);
+			writer.putChar((char)numExtTypeAreaTypes);
+			writer.putChar((char)numExtTypePointTypes);
 		}
 
 		if (getHeaderLength() > 154) {
@@ -318,20 +323,39 @@ public class TREHeader extends CommonHeader {
 		points.inc();
 	}
 
-	protected int getMapId() {
-		return mapId;
+	public void setExtTypeOffsetsPos(int pos) {
+		extTypeOffsets.setPosition(pos);
 	}
 
-	protected void setDisplayPriority(int displayPriority) {
-		this.displayPriority = displayPriority;
+	public void incExtTypeOffsetsSize() {
+		extTypeOffsets.inc();
+	}
+
+	public void setExtTypeOverviewsPos(int pos) {
+		extTypeOverviews.setPosition(pos);
+	}
+
+	public void incExtTypeOverviewsSize() {
+		extTypeOverviews.inc();
+	}
+
+	public void incNumExtTypeAreaTypes() {
+		++numExtTypeAreaTypes;
+	}
+
+	public void incNumExtTypeLineTypes() {
+		++numExtTypeLineTypes;
+	}
+	public void incNumExtTypePointTypes() {
+		++numExtTypePointTypes;
 	}
 
-	public void setTre7Pos(int pos) {
-		tre7.setPosition(pos);
+	protected int getMapId() {
+		return mapId;
 	}
 
-	public void incTre7() {
-		tre7.inc();
+	protected void setDisplayPriority(int displayPriority) {
+		this.displayPriority = displayPriority;
 	}
 
 	public int getDisplayPriority() {
diff --git a/src/uk/me/parabola/mkgmap/build/MapArea.java b/src/uk/me/parabola/mkgmap/build/MapArea.java
index 3be65cf..36b4b0e 100644
--- a/src/uk/me/parabola/mkgmap/build/MapArea.java
+++ b/src/uk/me/parabola/mkgmap/build/MapArea.java
@@ -389,6 +389,10 @@ public class MapArea implements MapDataSource {
 	 * @param kind What kind of element this is KIND_POINT etc.
 	 */
 	private void addSize(MapElement p, int[] sizes, int kind) {
+
+		if(p.hasExtendedType())
+			return;
+
 		int res = p.getMinResolution();
 		if (res > MAX_RESOLUTION)
 			return;
diff --git a/src/uk/me/parabola/mkgmap/build/MapBuilder.java b/src/uk/me/parabola/mkgmap/build/MapBuilder.java
index 3b06b3a..efe7899 100644
--- a/src/uk/me/parabola/mkgmap/build/MapBuilder.java
+++ b/src/uk/me/parabola/mkgmap/build/MapBuilder.java
@@ -174,7 +174,7 @@ public class MapBuilder implements Configurable {
 		treFile.setLastRgnPos(rgnFile.position() - RGNHeader.HEADER_LEN);
 
 		rgnFile.write();
-		treFile.write();
+		treFile.write(rgnFile.haveExtendedTypes());
 		treFile.writePost();
 		lblFile.write();
 		lblFile.writePost();
@@ -628,6 +628,8 @@ public class MapBuilder implements Configurable {
 		processLines(map, div, lines);
 		processShapes(map, div, shapes);
 
+		div.endDivision();
+
 		return div;
 	}
 
@@ -745,19 +747,21 @@ public class MapBuilder implements Configurable {
 				p.setPOIRecord(r);
 
 			map.addMapObject(p);
-			if(name != null && div.getZoom().getLevel() == 0) {
-				if(pointIndex > 255)
-					log.error("FIXME - too many POIs in group");
-				else if(point.isExit()) {
-					Exit e = ((MapExitPoint)point).getExit();
-					if(e != null)
-						e.getHighway().addExitPoint(name, pointIndex, div);
+			if(!point.hasExtendedType()) {
+				if(name != null && div.getZoom().getLevel() == 0) {
+					if(pointIndex > 255)
+						log.error("FIXME - too many POIs in group");
+					else if(point.isExit()) {
+						Exit e = ((MapExitPoint)point).getExit();
+						if(e != null)
+							e.getHighway().addExitPoint(name, pointIndex, div);
+					}
+					else
+						lbl.createPOIIndex(name, pointIndex, div, point.getType());
 				}
-				else
-					lbl.createPOIIndex(name, pointIndex, div, point.getType());
 
+				++pointIndex;
 			}
-			++pointIndex;
 		}
 
 		if (haveIndPoints) {
@@ -946,6 +950,8 @@ public class MapBuilder implements Configurable {
 			assert line.getPoints().size() < 255 : "too many points";
 
 			Polyline pl = div.createLine(line.getName(), line.getRef());
+			if(!element.hasExtendedType())
+				div.setPolylineNumber(pl);
 			pl.setDirection(line.isDirection());
 
 			for (Coord co : line.getPoints())
diff --git a/src/uk/me/parabola/mkgmap/general/MapElement.java b/src/uk/me/parabola/mkgmap/general/MapElement.java
index 6678c6d..9d2e598 100644
--- a/src/uk/me/parabola/mkgmap/general/MapElement.java
+++ b/src/uk/me/parabola/mkgmap/general/MapElement.java
@@ -160,6 +160,14 @@ public abstract class MapElement {
 		this.type = type;
 	}
 
+	public boolean hasExtendedType() {
+		return hasExtendedType(type);
+	}
+
+	public static boolean hasExtendedType(int type) {
+		return type >= 0x010000;
+	}
+
 	/**
 	 * Get the 'location' of the element.  This is the mid point of the bounding
 	 * box for the element.  For a point, this will be the coordinates of the
diff --git a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
index 2a549f8..6e47fac 100644
--- a/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
+++ b/src/uk/me/parabola/mkgmap/osmstyle/StyledConverter.java
@@ -166,7 +166,8 @@ public class StyledConverter implements OsmConverter {
 		postConvertRules(way, foundType);
 
 		if (foundType.getFeatureKind() == GType.POLYLINE) {
-		    if(foundType.isRoad())
+		    if(foundType.isRoad() &&
+			   !MapElement.hasExtendedType(foundType.getType()))
 				addRoad(way, foundType);
 		    else
 				addLine(way, foundType);
_______________________________________________
mkgmap-dev mailing list
mkgmap-dev@lists.mkgmap.org.uk
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to