diff --git a/src/main/org/insa/graph/Graph.java b/src/main/org/insa/graph/Graph.java index a5c3db0..b96e5ea 100644 --- a/src/main/org/insa/graph/Graph.java +++ b/src/main/org/insa/graph/Graph.java @@ -14,14 +14,25 @@ public class Graph { // Nodes of the graph. private final List nodes; + // Graph information of this graph. + private final GraphInformation graphInfo; + /** * @param mapId ID of this graph. * @param list List of nodes for this graph. */ - public Graph(String mapId, String mapName, List list) { + public Graph(String mapId, String mapName, List list, GraphInformation graphInformation) { this.mapId = mapId; this.mapName = mapName; this.nodes = list; + this.graphInfo = graphInformation; + } + + /** + * @return GraphInformation of this graph. + */ + public GraphInformation getGraphInformation() { + return this.graphInfo; } /** @@ -31,26 +42,6 @@ public class Graph { return Collections.unmodifiableList(nodes); } - /** - * Find the closet node to the given point. - * - * @param point - * - * @return Closest node to the given point. - */ - public Node findClosestNode(Point point) { - Node node = null; - double minDis = Double.POSITIVE_INFINITY; - for (int n = 0; n < nodes.size(); ++n) { - double dis = point.distanceTo(nodes.get(n).getPoint()); - if (dis < minDis) { - node = nodes.get(n); - minDis = dis; - } - } - return node; - } - /** * @return Map ID of this graph. */ diff --git a/src/main/org/insa/graph/GraphInformation.java b/src/main/org/insa/graph/GraphInformation.java new file mode 100644 index 0000000..1d49b40 --- /dev/null +++ b/src/main/org/insa/graph/GraphInformation.java @@ -0,0 +1,39 @@ +package org.insa.graph; + +/** + * Utility class that stores some information for a graph that are no easy to + * access quickly. + * + */ +public class GraphInformation { + + // Maximum speed on this graph (in kmph). + private final int maximumSpeed; + + // Maximum length of any arc on this graph. + private final int maximumLength; + + /** + * @param maximumSpeed + * @param maximumLength + */ + public GraphInformation(int maximumSpeed, int maximumLength) { + this.maximumLength = maximumLength; + this.maximumSpeed = maximumSpeed; + } + + /** + * @return Maximum speed of any arc in the graph. + */ + public int getMaximumSpeed() { + return this.maximumSpeed; + } + + /** + * @return Maximum length of any arc in the graph. + */ + public int getMaximumLength() { + return this.maximumLength; + } + +} diff --git a/src/main/org/insa/graph/io/BinaryGraphReaderInsa2016.java b/src/main/org/insa/graph/io/BinaryGraphReaderInsa2016.java deleted file mode 100644 index 5711006..0000000 --- a/src/main/org/insa/graph/io/BinaryGraphReaderInsa2016.java +++ /dev/null @@ -1,197 +0,0 @@ -package org.insa.graph.io; - -import java.io.DataInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; - -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.AccessRestriction; -import org.insa.graph.RoadInformation.RoadType; - -public class BinaryGraphReaderInsa2016 extends BinaryReader implements GraphReader { - - // 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 BinaryGraphReaderInsa2016(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 nodes = new ArrayList(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 points = new ArrayList(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. - new Arc(orig, dest, length, info, points); - - // And reverse arc if its a two-way road. - if (!info.isOneWay()) { - // Add without segments. - ArrayList rPoints = new ArrayList(points); - Collections.reverse(rPoints); - new Arc(dest, orig, length, info, rPoints); - } - - } - } - } - - // Check format. - checkByteOrThrow(253); - - return new Graph(Integer.toHexString(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), new AccessRestriction(), (x & 0x80) > 0, - (x & 0x7F) * 5, dis.readUTF()); - } - -} diff --git a/src/main/org/insa/graph/io/BinaryGraphReaderInsa2018.java b/src/main/org/insa/graph/io/BinaryGraphReaderInsa2018.java index e6262ba..a107d80 100644 --- a/src/main/org/insa/graph/io/BinaryGraphReaderInsa2018.java +++ b/src/main/org/insa/graph/io/BinaryGraphReaderInsa2018.java @@ -9,6 +9,7 @@ import java.util.Map; import org.insa.graph.Arc; import org.insa.graph.Graph; +import org.insa.graph.GraphInformation; import org.insa.graph.Node; import org.insa.graph.Point; import org.insa.graph.RoadInformation; @@ -63,8 +64,7 @@ public class BinaryGraphReaderInsa2018 extends BinaryReader implements GraphRead allowedModes.put(AccessMode.MOTORCAR, (access & MASK_MOTORCAR) != 0); allowedModes.put(AccessMode.BUS, (access & MASK_BUS) != 0); - return new AccessRestriction((access & MASK_PRIVATE) != 0, - (access & MASK_PUBLIC_TRANSPORT) != 0, allowedModes); + return new AccessRestriction((access & MASK_PRIVATE) != 0, (access & MASK_PUBLIC_TRANSPORT) != 0, allowedModes); } /** @@ -138,9 +138,7 @@ public class BinaryGraphReaderInsa2018 extends BinaryReader implements GraphRead mapId = "0x" + Integer.toHexString(dis.readInt()); } else { - byte[] byteId = new byte[MAP_ID_FIELD_LENGTH]; - dis.read(byteId); - mapId = new String(byteId, "UTF-8"); + mapId = readFixedLengthString(MAP_ID_FIELD_LENGTH, "UTF-8"); mapName = dis.readUTF(); } @@ -177,16 +175,21 @@ public class BinaryGraphReaderInsa2018 extends BinaryReader implements GraphRead // Read observers.forEach((observer) -> observer.notifyStartReadingDescriptors(nbDesc)); + int maxSpeed = 0; for (int descr = 0; descr < nbDesc; ++descr) { final RoadInformation roadinf = readRoadInformation(); descs[descr] = roadinf; observers.forEach((observer) -> observer.notifyNewDescriptorRead(roadinf)); + + // Update max speed + maxSpeed = Math.max(roadinf.getMaximumSpeed(), maxSpeed); } // Check format. checkByteOrThrow(254); // Read successors and convert to arcs. + int maxLength = 0; final int copyNbTotalSuccesors = nbTotalSuccessors; // Stupid Java... observers.forEach((observer) -> observer.notifyStartReadingArcs(copyNbTotalSuccesors)); for (int node = 0; node < nbNodes; ++node) { @@ -200,6 +203,7 @@ public class BinaryGraphReaderInsa2018 extends BinaryReader implements GraphRead // Length of the arc. int length = dis.readUnsignedShort(); + maxLength = Math.max(length, maxLength); // Number of segments. int nbSegments = dis.readUnsignedShort(); @@ -214,8 +218,7 @@ public class BinaryGraphReaderInsa2018 extends BinaryReader implements GraphRead float dlon = (dis.readShort()) / 2.0e5f; float dlat = (dis.readShort()) / 2.0e5f; - points.add(new Point(lastPoint.getLongitude() + dlon, - lastPoint.getLatitude() + dlat)); + points.add(new Point(lastPoint.getLongitude() + dlon, lastPoint.getLatitude() + dlat)); } points.add(nodes.get(destNode).getPoint()); @@ -243,7 +246,9 @@ public class BinaryGraphReaderInsa2018 extends BinaryReader implements GraphRead observers.forEach((observer) -> observer.notifyEndReading()); - return new Graph(mapId, mapName, nodes); + this.dis.close(); + + return new Graph(mapId, mapName, nodes, new GraphInformation(maxSpeed, maxLength)); } /** @@ -258,8 +263,7 @@ public class BinaryGraphReaderInsa2018 extends BinaryReader implements GraphRead if (getCurrentVersion() >= 6) { access = toAccessInformation(dis.readUnsignedShort()); } - return new RoadInformation(toRoadType(type), access, (x & 0x80) > 0, (x & 0x7F) * 5, - dis.readUTF()); + return new RoadInformation(toRoadType(type), access, (x & 0x80) > 0, (x & 0x7F) * 5, dis.readUTF()); } } diff --git a/src/main/org/insa/graph/io/BinaryPathReader.java b/src/main/org/insa/graph/io/BinaryPathReader.java index 1f62fbc..28c8af4 100644 --- a/src/main/org/insa/graph/io/BinaryPathReader.java +++ b/src/main/org/insa/graph/io/BinaryPathReader.java @@ -26,10 +26,7 @@ public class BinaryPathReader extends BinaryReader implements PathReader { checkVersionOrThrow(dis.readInt()); // Read map ID and check against graph. - byte[] mapIdBytes = new byte[BinaryGraphReaderInsa2018.MAP_ID_FIELD_LENGTH]; - dis.read(mapIdBytes); - - String mapId = new String(mapIdBytes, "UTF-8"); + String mapId = readFixedLengthString(BinaryGraphReaderInsa2018.MAP_ID_FIELD_LENGTH, "UTF-8"); if (!mapId.equals(graph.getMapId())) { throw new MapMismatchException(mapId, graph.getMapId()); diff --git a/src/main/org/insa/graph/io/BinaryReader.java b/src/main/org/insa/graph/io/BinaryReader.java index 5f27b39..ad4745d 100644 --- a/src/main/org/insa/graph/io/BinaryReader.java +++ b/src/main/org/insa/graph/io/BinaryReader.java @@ -76,6 +76,22 @@ public abstract class BinaryReader { } } + /** + * Read an bytes array of fixed length from the input and convert it to a string + * using the given charset, removing any trailing '\0'. + * + * @param length + * @param charset + * + * @return an UTF-8 string read from the input. + * @throws IOException + */ + protected String readFixedLengthString(int length, String charset) throws IOException { + byte[] bytes = new byte[length]; + this.dis.read(bytes); + return new String(bytes, "UTF-8").trim(); + } + /** * Read 24 bits from the stream and return the corresponding integer value. *