Rev 3366 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Copyright (C) 2008 Steve Ratcliffe
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 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.
*
*
* Author: Steve Ratcliffe
* Create date: 06-Jul-2008
*/
package uk.me.parabola.imgfmt.app.net;
import java.util.Arrays;
import uk.me.parabola.imgfmt.ReadFailedException;
import uk.me.parabola.imgfmt.app.CommonHeader;
import uk.me.parabola.imgfmt.app.ImgFileReader;
import uk.me.parabola.imgfmt.app.ImgFileWriter;
import uk.me.parabola.imgfmt.app.Section;
/**
* Header information for the NOD file.
*
* This is a routing network for the map.
*
* @author Steve Ratcliffe
*/
public class NODHeader
extends CommonHeader
{
public static final int HEADER_LEN =
127;
static final char DEF_ALIGN =
6;
private static final char BOUNDARY_ITEM_SIZE =
9;
private final Section nodes =
new Section
();
private final Section roads =
new Section
(nodes
);
private final Section boundary =
new Section
(roads, BOUNDARY_ITEM_SIZE
);
private final Section highClassBoundary =
new Section
(boundary
);
private final int[] classBoundaries =
new int[5];
private int flags
;
private int align
;
private int mult1
;
private int tableARecordLen
;
private boolean driveOnLeft
;
public NODHeader
() {
super(HEADER_LEN,
"GARMIN NOD");
Arrays.
fill(classBoundaries,
Integer.
MAX_VALUE);
}
/**
* Read the rest of the header. Specific to the given file. It is guaranteed
* that the file position will be set to the correct place before this is
* called.
*
* @param reader The header is read from here.
*/
protected void readFileHeader
(ImgFileReader reader
) throws ReadFailedException
{
nodes.
readSectionInfo(reader,
false);
flags = reader.
getChar();
reader.
getChar();
align = reader.
get();
mult1 = reader.
get();
tableARecordLen = reader.
getChar();
roads.
readSectionInfo(reader,
false);
reader.
getInt();
boundary.
readSectionInfo(reader,
true);
reader.
getInt();
if (getHeaderLength
() > 0x3f
) {
highClassBoundary.
readSectionInfo(reader,
false);
classBoundaries
[0] = reader.
getInt();
classBoundaries
[1] = classBoundaries
[0] + reader.
getInt();
classBoundaries
[2] = classBoundaries
[1] + reader.
getInt();
classBoundaries
[3] = classBoundaries
[2] + reader.
getInt();
classBoundaries
[4] = classBoundaries
[3] + reader.
getInt();
}
}
/**
* Write the rest of the header. It is guaranteed that the writer will be set
* to the correct position before calling.
*
* @param writer The header is written here.
*/
// multiplier shift for road + arc length values, the smaller the shift the higher the precision and NOD size
// as it has an influence on the number of bits needed to encode a length
final static int DISTANCE_MULT_SHIFT =
1; // 0..7 1 seems to be a good compromise
final static int DISTANCE_MULT =
1 << DISTANCE_MULT_SHIFT
;
protected void writeFileHeader
(ImgFileWriter writer
) {
nodes.
setPosition(HEADER_LEN
);
nodes.
writeSectionInfo(writer
);
// 0x0001 always set, meaning ?
// 0x0002 (enable turn restrictions)
// 0x001c meaning ?
// 0x00E0 distance multiplier, effects predicted travel time
int flags = 0x0207
;
assert Integer.
bitCount(DISTANCE_MULT
) ==
1;
assert DISTANCE_MULT_SHIFT
< 8;
flags |= DISTANCE_MULT_SHIFT
<< 5;
if(driveOnLeft
)
flags |= 0x0100
;
writer.
putInt(flags
);
byte align = DEF_ALIGN
;
writer.
put(align
);
writer.
put((byte) 0); // pointer multiplier
writer.
putChar((char) 5);
roads.
writeSectionInfo(writer
);
writer.
putInt(0);
boundary.
writeSectionInfo(writer
);
// new fields for header length > 0x3f
writer.
putInt(2); // no other value spotted, meaning ?
highClassBoundary.
writeSectionInfo(writer
);
writer.
putInt(classBoundaries
[0]);
for (int i =
1; i
< classBoundaries.
length; i++
){
writer.
putInt(classBoundaries
[i
] - classBoundaries
[i-
1]);
}
}
private static final double UNIT_TO_METER =
2.4;
public static int metersToRaw
(double m
) {
double d = m /
(DISTANCE_MULT
* UNIT_TO_METER
);
return (int) Math.
round(d
);
}
public int getNodeStart
() {
return nodes.
getPosition();
}
public void setNodeStart
(int start
) {
nodes.
setPosition(start
);
}
public int getNodeSize
() {
return nodes.
getSize();
}
public void setNodeSize
(int size
) {
nodes.
setSize(size
);
}
public Section getNodeSection
() {
return nodes
;
}
public void setRoadSize
(int size
) {
roads.
setSize(size
);
}
public Section getRoadSection
() {
return roads
;
}
public void setBoundarySize
(int size
) {
boundary.
setSize(size
);
}
public Section getBoundarySection
() {
return boundary
;
}
public void setHighClassBoundarySize
(int size
) {
highClassBoundary.
setSize(size
);
}
public Section getHighClassBoundary
() {
return highClassBoundary
;
}
public int[] getClassBoundaries
() {
return classBoundaries
;
}
public void setDriveOnLeft
(boolean dol
) {
driveOnLeft = dol
;
}
public int getFlags
() {
return flags
;
}
public int getAlign
() {
return align
;
}
public int getMult1
() {
return mult1
;
}
public int getTableARecordLen
() {
return tableARecordLen
;
}
}