177 lines
4.7 KiB
Java
177 lines
4.7 KiB
Java
package org.insa.graph.io;
|
|
|
|
import java.io.DataInputStream;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
|
|
import org.insa.graph.Arc;
|
|
import org.insa.graph.Graph;
|
|
import org.insa.graph.Node;
|
|
import org.insa.graph.Point;
|
|
import org.insa.graph.RoadInformation;
|
|
import org.insa.graph.RoadInformation.RoadType;
|
|
|
|
public class BinaryGraphReader extends BinaryReader implements AbstractGraphReader {
|
|
|
|
// Map version and magic number targeted for this reader.
|
|
private static final int VERSION = 4;
|
|
private static final int MAGIC_NUMBER = 0xbacaff;
|
|
|
|
/**
|
|
* Convert a character to its corresponding road type.
|
|
*
|
|
* @param ch Character to convert.
|
|
*
|
|
* @return Road type corresponding to ch.
|
|
*
|
|
* @see http://wiki.openstreetmap.org/wiki/Highway_tag_usage.
|
|
*/
|
|
public static RoadType toRoadType(char ch) {
|
|
switch (ch) {
|
|
case 'a': return RoadType.MOTORWAY;
|
|
case 'b': return RoadType.TRUNK;
|
|
case 'c': return RoadType.PRIMARY;
|
|
case 'd': return RoadType.SECONDARY;
|
|
case 'e': return RoadType.MOTORWAY_LINK;
|
|
case 'f': return RoadType.TRUNK_LINK;
|
|
case 'g': return RoadType.PRIMARY_LINK;
|
|
case 'h': return RoadType.SECONDARY_LINK;
|
|
case 'i': return RoadType.TERTIARY;
|
|
case 'j': return RoadType.RESIDENTIAL;
|
|
case 'k': return RoadType.UNCLASSIFIED;
|
|
case 'l': return RoadType.ROAD;
|
|
case 'm': return RoadType.LIVING_STREET;
|
|
case 'n': return RoadType.SERVICE;
|
|
case 'o': return RoadType.ROUNDABOUT;
|
|
case 'z': return RoadType.COASTLINE;
|
|
}
|
|
return RoadType.UNCLASSIFIED;
|
|
}
|
|
|
|
/**
|
|
* Create a new BinaryGraphReader using the given DataInputStream.
|
|
*
|
|
* @param dis
|
|
*/
|
|
public BinaryGraphReader(DataInputStream dis) {
|
|
super(MAGIC_NUMBER, VERSION, dis);
|
|
}
|
|
|
|
@Override
|
|
public Graph read() throws IOException {
|
|
|
|
// Read and check magic number and file version.
|
|
checkMagicNumberOrThrow(dis.readInt());
|
|
checkVersionOrThrow(dis.readInt());
|
|
|
|
// Read map id.
|
|
int mapId = dis.readInt();
|
|
|
|
// Read zone.
|
|
int graphZone = dis.readInt();
|
|
|
|
// Number of descriptors and nodes.
|
|
int nbDesc = dis.readInt();
|
|
int nbNodes = dis.readInt();
|
|
|
|
// Number of successors for each nodes.
|
|
int[] nbSuccessors = new int[nbNodes];
|
|
|
|
// Construct an array list with initial capacity of nbNodes.
|
|
ArrayList<Node> nodes = new ArrayList<Node>(nbNodes);
|
|
|
|
// Read nodes.
|
|
for (int node = 0; node < nbNodes; ++node) {
|
|
float longitude = ((float)dis.readInt ()) / 1E6f;
|
|
float latitude = ((float)dis.readInt ()) / 1E6f;
|
|
nbSuccessors[node] = dis.readUnsignedByte();
|
|
nodes.add(new Node(node, new Point(longitude, latitude)));
|
|
}
|
|
|
|
// Check format.
|
|
checkByteOrThrow(255);
|
|
|
|
// Read descriptors.
|
|
RoadInformation[] descs = new RoadInformation[nbDesc];
|
|
|
|
// Read
|
|
for (int descr = 0; descr < nbDesc; ++descr) {
|
|
descs[descr] = readRoadInformation();
|
|
}
|
|
|
|
// Check format.
|
|
checkByteOrThrow(254);
|
|
|
|
// Read successors and convert to arcs.
|
|
for (int node = 0; node < nbNodes; ++node) {
|
|
for (int succ = 0; succ < nbSuccessors[node]; ++succ) {
|
|
|
|
// Read destination zone.
|
|
int destZone = dis.readUnsignedByte();
|
|
|
|
// Read target node number.
|
|
int destNode = this.read24bits();
|
|
|
|
// Read information number.
|
|
int descrNum = this.read24bits();
|
|
|
|
// Length of the arc.
|
|
int length = dis.readUnsignedShort();
|
|
|
|
// Number of segments.
|
|
int nbSegments = dis.readUnsignedShort();
|
|
|
|
// Chain of points corresponding to the segments.
|
|
ArrayList<Point> points = new ArrayList<Point>(nbSegments + 2);
|
|
points.add(nodes.get(node).getPoint());
|
|
|
|
for (int seg = 0; seg < nbSegments; ++seg) {
|
|
Point lastPoint = points.get(points.size() - 1);
|
|
|
|
float dlon = (dis.readShort()) / 2.0e5f;
|
|
float dlat = (dis.readShort()) / 2.0e5f;
|
|
|
|
points.add(new Point(lastPoint.getLongitude() + dlon,
|
|
lastPoint.getLatitude() + dlat));
|
|
}
|
|
|
|
points.add(nodes.get(destNode).getPoint());
|
|
|
|
if (graphZone == destZone) {
|
|
|
|
RoadInformation info = descs[descrNum];
|
|
Node orig = nodes.get(node);
|
|
Node dest = nodes.get(destNode);
|
|
|
|
// Add successor to initial arc.
|
|
orig.addSuccessor(new Arc(dest, length, info, points));
|
|
|
|
// And reverse arc if its a two-way road.
|
|
if (!info.isOneWay()) {
|
|
// Add without segments.
|
|
dest.addSuccessor(new Arc(orig, length, info));
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check format.
|
|
checkByteOrThrow(253);
|
|
|
|
return new Graph(mapId, nodes);
|
|
}
|
|
|
|
/**
|
|
* Read the next road information from the stream.
|
|
*
|
|
* @throws IOException
|
|
*/
|
|
private RoadInformation readRoadInformation() throws IOException {
|
|
char type = (char)dis.readUnsignedByte();
|
|
int x = dis.readUnsignedByte() ;
|
|
return new RoadInformation(toRoadType(type), (x & 0x80) > 0, (x & 0x7F) * 5, dis.readUTF());
|
|
}
|
|
|
|
}
|