Switch to Maven project.
This commit is contained in:
14
be-graphes-model/pom.xml
Normal file
14
be-graphes-model/pom.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0"?>
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.insa.graphs</groupId>
|
||||
<artifactId>be-graphes-all</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>be-graphes-model</artifactId>
|
||||
<name>be-graphes-model</name>
|
||||
</project>
|
@@ -0,0 +1,236 @@
|
||||
package org.insa.graphs.model;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Class containing access restrictions for roads/arcs.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This class maps transport modes to their restriction and provide interface
|
||||
* based on EnumSet to query restrictions.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* To each transport is associated at most one restriction per road (no
|
||||
* restriction corresponds to {@link AccessRestriction#UNKNOWN} but a road can
|
||||
* have different restrictions for different modes.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public class AccessRestrictions {
|
||||
|
||||
/**
|
||||
* Enumeration representing the available transport modes.
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://wiki.openstreetmap.org/wiki/Key:access#Transport_mode_restrictions">OpenStreetMap
|
||||
* reference for access modes.</a>
|
||||
*/
|
||||
public enum AccessMode {
|
||||
|
||||
/**
|
||||
* Access mode corresponding to pedestrians.
|
||||
*/
|
||||
FOOT,
|
||||
|
||||
/**
|
||||
* Access mode corresponding to bicycles (non-motorized).
|
||||
*/
|
||||
BICYCLE,
|
||||
|
||||
/**
|
||||
* Access mode corresponding to small motorcycles (limited speed).
|
||||
*/
|
||||
SMALL_MOTORCYCLE,
|
||||
|
||||
/**
|
||||
* Access mode corresponding to agricultural vehicles.
|
||||
*/
|
||||
AGRICULTURAL,
|
||||
|
||||
/**
|
||||
* Access mode corresponding to motorcycles.
|
||||
*/
|
||||
MOTORCYCLE,
|
||||
|
||||
/**
|
||||
* Access mode corresponding to motorcars.
|
||||
*/
|
||||
MOTORCAR,
|
||||
|
||||
/**
|
||||
* Access mode corresponding to heavy transportation vehicles.
|
||||
*/
|
||||
HEAVY_GOODS,
|
||||
|
||||
/**
|
||||
* Access mode corresponding to public transport vehicles.
|
||||
*/
|
||||
PUBLIC_TRANSPORT;
|
||||
|
||||
/**
|
||||
* {@code EnumSet} containing all possible transport modes.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public static final EnumSet<AccessMode> ALL = EnumSet.allOf(AccessMode.class);
|
||||
|
||||
/**
|
||||
* {@code EnumSet} containing all vehicle transport modes.
|
||||
*
|
||||
*/
|
||||
public static final EnumSet<AccessMode> VEHICLE = EnumSet.range(AccessMode.BICYCLE,
|
||||
AccessMode.PUBLIC_TRANSPORT);
|
||||
|
||||
/**
|
||||
* {@code EnumSet} containing all motorized vehicle transport modes.
|
||||
*
|
||||
*/
|
||||
public static final EnumSet<AccessMode> MOTOR_VEHICLE = EnumSet
|
||||
.range(AccessMode.SMALL_MOTORCYCLE, AccessMode.PUBLIC_TRANSPORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Possible restrictions for the roads/arcs.
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://wiki.openstreetmap.org/wiki/Key:access#Transport_mode_restrictions">OpenStreetMap
|
||||
* reference for access restrictions.</a>
|
||||
*/
|
||||
public enum AccessRestriction {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
ALLOWED,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FORBIDDEN,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PRIVATE,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
DESTINATION,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
DELIVERY,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
CUSTOMERS,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FORESTRY,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UNKNOWN;
|
||||
|
||||
/**
|
||||
* {@code EnumSet} corresponding to restrictions that are not totally private.
|
||||
*
|
||||
*/
|
||||
public static final EnumSet<AccessRestriction> ALLOWED_FOR_SOMETHING = EnumSet.of(
|
||||
AccessRestriction.ALLOWED, AccessRestriction.DESTINATION,
|
||||
AccessRestriction.DESTINATION, AccessRestriction.DELIVERY,
|
||||
AccessRestriction.CUSTOMERS, AccessRestriction.FORESTRY);
|
||||
|
||||
}
|
||||
|
||||
// Map mode -> restriction
|
||||
private final EnumMap<AccessMode, AccessRestriction> restrictions;
|
||||
|
||||
/**
|
||||
* Create new AccessRestrictions instances with unknown restrictions.
|
||||
*/
|
||||
public AccessRestrictions() {
|
||||
this.restrictions = new EnumMap<>(AccessMode.class);
|
||||
for (AccessMode mode: AccessMode.values()) {
|
||||
this.restrictions.put(mode, AccessRestriction.UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new AccessRestrictions instances with the given restrictions.
|
||||
*
|
||||
* @param restrictions Map of restrictions for this instance of
|
||||
* AccessRestrictions.
|
||||
*/
|
||||
public AccessRestrictions(EnumMap<AccessMode, AccessRestriction> restrictions) {
|
||||
this.restrictions = restrictions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the restriction corresponding to the given mode.
|
||||
*
|
||||
* @param mode Mode for which the restriction should be retrieved.
|
||||
*
|
||||
* @return Restriction for the given mode.
|
||||
*/
|
||||
public AccessRestriction getRestrictionFor(AccessMode mode) {
|
||||
return restrictions.getOrDefault(mode, AccessRestriction.UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the restriction associated with the given mode is one of the given
|
||||
* restrictions.
|
||||
*
|
||||
* @param mode Mode for which to check the restrictions.
|
||||
* @param restrictions List of queried restrictions for the mode.
|
||||
*
|
||||
* @return {@code true} if the restriction of the given mode is one of the given
|
||||
* restrictions.
|
||||
*/
|
||||
public boolean isAllowedForAny(AccessMode mode, EnumSet<AccessRestriction> restrictions) {
|
||||
return restrictions.contains(getRestrictionFor(mode));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the restriction for the given mode corresponds to the given
|
||||
* restriction.
|
||||
*
|
||||
* @param mode Mode for which the restriction should be checked.
|
||||
* @param restriction Restriction to check against.
|
||||
*
|
||||
* @return {@code true} if the restriction of the given mode corresponds to the
|
||||
* given restriction.
|
||||
*/
|
||||
public boolean isAllowedFor(AccessMode mode, AccessRestriction restriction) {
|
||||
return getRestrictionFor(mode).equals(restriction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the restriction associated to each given mode is one of the
|
||||
* restrictions. The restriction may not be the same for all modes.
|
||||
*
|
||||
* @param modes Modes for which restrictions should be checked.
|
||||
* @param restrictions Set of wanted restrictions for the modes.
|
||||
*
|
||||
* @return {@code true} if all the given modes are allowed for any of the given
|
||||
* restrictions.
|
||||
*/
|
||||
public boolean areAllAllowedForAny(EnumSet<AccessMode> modes,
|
||||
EnumSet<AccessRestriction> restrictions) {
|
||||
boolean allowed = true;
|
||||
for (AccessMode mode: modes) {
|
||||
allowed = allowed && isAllowedForAny(mode, restrictions);
|
||||
}
|
||||
return allowed;
|
||||
}
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
package org.insa.graphs.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Interface representing an arc in the graph. {@code Arc} is an interface and
|
||||
* not a class to allow us to represent two-ways roads in a memory efficient
|
||||
* manner (without having to duplicate attributes).
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Arc should never be created manually but always using the
|
||||
* {@link Node#linkNodes(Node, Node, float, RoadInformation, java.util.ArrayList)}
|
||||
* method to ensure proper instantiation of the {@link ArcForward} and
|
||||
* {@link ArcBackward} classes.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public abstract class Arc {
|
||||
|
||||
/**
|
||||
* @return Origin node of this arc.
|
||||
*/
|
||||
public abstract Node getOrigin();
|
||||
|
||||
/**
|
||||
* @return Destination node of this arc.
|
||||
*/
|
||||
public abstract Node getDestination();
|
||||
|
||||
/**
|
||||
* @return Length of this arc, in meters.
|
||||
*/
|
||||
public abstract float getLength();
|
||||
|
||||
/**
|
||||
* Compute the time required to travel this arc if moving at the given speed.
|
||||
*
|
||||
* @param speed Speed to compute the travel time.
|
||||
*
|
||||
* @return Time (in seconds) required to travel this arc at the given speed (in
|
||||
* kilometers-per-hour).
|
||||
*/
|
||||
public double getTravelTime(double speed) {
|
||||
return getLength() * 3600.0 / (speed * 1000.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute and return the minimum time required to travel this arc, or the time
|
||||
* required to travel this arc at the maximum speed allowed.
|
||||
*
|
||||
* @return Minimum time required to travel this arc, in seconds.
|
||||
*
|
||||
* @see Arc#getTravelTime(double)
|
||||
*/
|
||||
public double getMinimumTravelTime() {
|
||||
return getTravelTime(getRoadInformation().getMaximumSpeed());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Road information for this arc.
|
||||
*/
|
||||
public abstract RoadInformation getRoadInformation();
|
||||
|
||||
/**
|
||||
* @return Points representing segments of this arc.
|
||||
*/
|
||||
public abstract List<Point> getPoints();
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
package org.insa.graphs.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementation of Arc that represents a "backward" arc in a graph, i.e., an
|
||||
* arc that is the reverse of another one. This arc only holds a reference to
|
||||
* the original arc.
|
||||
*
|
||||
*/
|
||||
class ArcBackward extends Arc {
|
||||
|
||||
// Original arc
|
||||
private final Arc originalArc;
|
||||
|
||||
/**
|
||||
* Create a new backward arc which corresponds to the reverse arc of the given
|
||||
* arc.
|
||||
*
|
||||
* @param originalArc Original forwarc arc corresponding to this backward arc.
|
||||
*/
|
||||
protected ArcBackward(Arc originalArc) {
|
||||
this.originalArc = originalArc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getOrigin() {
|
||||
return this.originalArc.getDestination();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getDestination() {
|
||||
return this.originalArc.getOrigin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getLength() {
|
||||
return this.originalArc.getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoadInformation getRoadInformation() {
|
||||
return this.originalArc.getRoadInformation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Point> getPoints() {
|
||||
List<Point> pts = new ArrayList<>(this.originalArc.getPoints());
|
||||
Collections.reverse(pts);
|
||||
return pts;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
package org.insa.graphs.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementation of Arc that represents a "forward" arc in a graph, this is the
|
||||
* arc implementation that stores data relative to the arc.
|
||||
*
|
||||
*/
|
||||
class ArcForward extends Arc {
|
||||
|
||||
// Destination node.
|
||||
private final Node origin, destination;
|
||||
|
||||
// Length of the road (in meters).
|
||||
private final float length;
|
||||
|
||||
// Road information.
|
||||
private final RoadInformation info;
|
||||
|
||||
// Segments.
|
||||
private final List<Point> points;
|
||||
|
||||
/**
|
||||
* Create a new ArcForward with the given attributes.
|
||||
*
|
||||
* @param origin Origin of this arc.
|
||||
* @param dest Destination of this arc.
|
||||
* @param length Length of this arc (in meters).
|
||||
* @param roadInformation Road information for this arc.
|
||||
* @param points Points representing this arc.
|
||||
*/
|
||||
protected ArcForward(Node origin, Node dest, float length, RoadInformation roadInformation,
|
||||
List<Point> points) {
|
||||
this.origin = origin;
|
||||
this.destination = dest;
|
||||
this.length = length;
|
||||
this.info = roadInformation;
|
||||
this.points = points;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getOrigin() {
|
||||
return origin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoadInformation getRoadInformation() {
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Point> getPoints() {
|
||||
return Collections.unmodifiableList(points);
|
||||
}
|
||||
|
||||
}
|
131
be-graphes-model/src/main/java/org/insa/graphs/model/Graph.java
Normal file
131
be-graphes-model/src/main/java/org/insa/graphs/model/Graph.java
Normal file
@@ -0,0 +1,131 @@
|
||||
package org.insa.graphs.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Main graph class.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This class acts as a object-oriented <b>adjacency list</b> for a graph, i.e.,
|
||||
* it holds a list of nodes and each node holds a list of its successors.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public final class Graph {
|
||||
|
||||
// Map identifier.
|
||||
private final String mapId;
|
||||
|
||||
// Map name
|
||||
private final String mapName;
|
||||
|
||||
// Nodes of the graph.
|
||||
private final List<Node> nodes;
|
||||
|
||||
// Graph information of this graph.
|
||||
private final GraphStatistics graphStatistics;
|
||||
|
||||
/**
|
||||
* Create a new graph with the given ID, name, nodes and information.
|
||||
*
|
||||
* @param mapId ID of the map corresponding to this graph.
|
||||
* @param mapName Name of the map corresponding to this graph.
|
||||
* @param nodes List of nodes for this graph.
|
||||
* @param graphStatistics Information for this graph.
|
||||
*/
|
||||
public Graph(String mapId, String mapName, List<Node> nodes, GraphStatistics graphStatistics) {
|
||||
this.mapId = mapId;
|
||||
this.mapName = mapName;
|
||||
this.nodes = Collections.unmodifiableList(nodes);
|
||||
this.graphStatistics = graphStatistics;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The GraphStatistics instance associated with this graph.
|
||||
*/
|
||||
public GraphStatistics getGraphInformation() {
|
||||
return this.graphStatistics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the node with the given ID.
|
||||
*
|
||||
* Complexity: O(1).
|
||||
*
|
||||
* @param id ID of the node to fetch.
|
||||
*
|
||||
* @return Node with the given ID.
|
||||
*/
|
||||
public Node get(int id) {
|
||||
return this.nodes.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Number of nodes in this graph.
|
||||
*/
|
||||
public int size() {
|
||||
return this.nodes.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of nodes in this graph (unmodifiable).
|
||||
*
|
||||
* @see Collections#unmodifiableList(List)
|
||||
*/
|
||||
public List<Node> getNodes() {
|
||||
return this.nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ID of the map associated with this graph.
|
||||
*/
|
||||
public String getMapId() {
|
||||
return mapId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Name of the map associated with this graph.
|
||||
*/
|
||||
public String getMapName() {
|
||||
return mapName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Transpose graph of this graph.
|
||||
*/
|
||||
public Graph transpose() {
|
||||
ArrayList<Node> trNodes = new ArrayList<>(nodes.size());
|
||||
for (Node node: nodes) {
|
||||
trNodes.add(new Node(node.getId(), node.getPoint()));
|
||||
}
|
||||
for (Node node: nodes) {
|
||||
Node orig = trNodes.get(node.getId());
|
||||
for (Arc arc: node.getSuccessors()) {
|
||||
if (arc.getRoadInformation().isOneWay()) {
|
||||
Node dest = trNodes.get(arc.getDestination().getId());
|
||||
dest.addSuccessor(new ArcBackward(new ArcForward(orig, dest, arc.getLength(),
|
||||
arc.getRoadInformation(), arc.getPoints())));
|
||||
}
|
||||
else if (arc instanceof ArcForward) {
|
||||
Node dest = trNodes.get(arc.getDestination().getId());
|
||||
Arc newArc = new ArcForward(orig, dest, arc.getLength(),
|
||||
arc.getRoadInformation(), arc.getPoints());
|
||||
dest.addSuccessor(new ArcBackward(newArc));
|
||||
orig.addSuccessor(newArc);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Graph("R/" + mapId, mapName, trNodes, graphStatistics);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s[id=%s, name=%s, #nodes=%d]", getClass().getCanonicalName(),
|
||||
getMapId(), getMapName(), size());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,204 @@
|
||||
package org.insa.graphs.model;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Utility class that stores some statistics of graphs that are not easy to
|
||||
* access.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This class is used to provide constant ({@code O(1)}) access to information
|
||||
* in graph that do not change, and that usually require linear complexity to
|
||||
* compute.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public class GraphStatistics {
|
||||
|
||||
/**
|
||||
* Special value used to indicate that the graph has no maximum speed limit
|
||||
* (some roads are not limited).
|
||||
*
|
||||
*/
|
||||
public static final int NO_MAXIMUM_SPEED = -1;
|
||||
|
||||
/**
|
||||
* Class representing a bounding box for a graph (a rectangle that contains all
|
||||
* nodes in the graph).
|
||||
*
|
||||
*/
|
||||
public static class BoundingBox {
|
||||
|
||||
private final Point topLeft, bottomRight;
|
||||
|
||||
/**
|
||||
* Create a new BoundingBox represented by the given top-left and bottom-right
|
||||
* points.
|
||||
*
|
||||
* @param topLeft Top left corner of the bounding box.
|
||||
* @param bottomRight Bottom right corner of the bounding box.
|
||||
*/
|
||||
public BoundingBox(Point topLeft, Point bottomRight) {
|
||||
this.topLeft = topLeft;
|
||||
this.bottomRight = bottomRight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Bottom-right point of this bounding box.
|
||||
*/
|
||||
public Point getBottomRightPoint() {
|
||||
return bottomRight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Top-left point of this bounding box.
|
||||
*/
|
||||
public Point getTopLeftPoint() {
|
||||
return topLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new bounding box by extending the current one according to the given
|
||||
* value for each side.
|
||||
*
|
||||
* @param left Extra size to add to the left of the box.
|
||||
* @param top Extra size to add to the top of the box.
|
||||
* @param right Extra size to add to the right of the box.
|
||||
* @param bottom Extra size to add to the bottom of the box.
|
||||
*
|
||||
* @return New bounding box corresponding to an extension of the current one.
|
||||
*/
|
||||
public BoundingBox extend(float left, float top, float right, float bottom) {
|
||||
return new BoundingBox(
|
||||
new Point(this.topLeft.getLongitude() - left, this.topLeft.getLatitude() + top),
|
||||
new Point(this.bottomRight.getLongitude() + right,
|
||||
this.bottomRight.getLatitude() - bottom));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new bounding box by extending the current one according by the given
|
||||
* value on each side.
|
||||
*
|
||||
* @param size Extra size to add to each side of this box.
|
||||
*
|
||||
* @return New bounding box corresponding to an extension of the current one.
|
||||
*/
|
||||
public BoundingBox extend(float size) {
|
||||
return this.extend(size, size, size, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param point Point to check
|
||||
*
|
||||
* @return true if this box contains the given point.
|
||||
*/
|
||||
public boolean contains(Point point) {
|
||||
return this.bottomRight.getLatitude() <= point.getLatitude()
|
||||
&& this.topLeft.getLatitude() >= point.getLatitude()
|
||||
&& this.topLeft.getLongitude() <= point.getLongitude()
|
||||
&& this.bottomRight.getLongitude() >= point.getLongitude();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param other Box to intersect.
|
||||
*
|
||||
* @return true if this box contains the given box.
|
||||
*/
|
||||
public boolean contains(BoundingBox other) {
|
||||
return this.contains(other.bottomRight) && this.contains(other.topLeft);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BoundingBox(topLeft=" + this.topLeft + ", bottomRight=" + this.bottomRight
|
||||
+ ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Bounding box for this graph.
|
||||
private final BoundingBox boundingBox;
|
||||
|
||||
// Number of roads
|
||||
private final int nbRoadOneWay, nbRoadTwoWays;
|
||||
|
||||
// Maximum speed on this graph (in kmph).
|
||||
private final int maximumSpeed;
|
||||
|
||||
// Maximum length of any arc on this graph.
|
||||
private final float maximumLength;
|
||||
|
||||
/**
|
||||
* Create a new GraphStatistics instance with the given value.
|
||||
*
|
||||
* @param boundingBox Bounding-box for the graph.
|
||||
* @param nbRoadOneWay Number of one-way roads in the graph.
|
||||
* @param nbRoadTwoWays Number of two-ways roads in the graph.
|
||||
* @param maximumSpeed Maximum speed of any road of the graph. You can use
|
||||
* {@link #NO_MAXIMUM_SPEED} to indicate that the graph has no maximum
|
||||
* speed limit.
|
||||
* @param maximumLength Maximum length of any arc of the graph.
|
||||
*/
|
||||
public GraphStatistics(BoundingBox boundingBox, int nbRoadOneWay, int nbRoadTwoWays,
|
||||
int maximumSpeed, float maximumLength) {
|
||||
this.boundingBox = boundingBox;
|
||||
this.nbRoadOneWay = nbRoadOneWay;
|
||||
this.nbRoadTwoWays = nbRoadTwoWays;
|
||||
this.maximumLength = maximumLength;
|
||||
this.maximumSpeed = maximumSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The bounding box for this graph.
|
||||
*/
|
||||
public BoundingBox getBoundingBox() {
|
||||
return this.boundingBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Amount of one-way roads in this graph.
|
||||
*/
|
||||
public int getOneWayRoadCount() {
|
||||
return this.nbRoadOneWay;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Amount of two-ways roads in this graph.
|
||||
*/
|
||||
public int getTwoWaysRoadCount() {
|
||||
return this.nbRoadTwoWays;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Number of arcs in this graph.
|
||||
*
|
||||
* @see #getOneWayRoadCount()
|
||||
* @see #getTwoWaysRoadCount()
|
||||
*/
|
||||
public int getArcCount() {
|
||||
return getOneWayRoadCount() + 2 * getTwoWaysRoadCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this graph has a maximum speed limit, false otherwise.
|
||||
*/
|
||||
public boolean hasMaximumSpeed() {
|
||||
return this.maximumLength != NO_MAXIMUM_SPEED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Maximum speed of any arc in the graph, or {@link #NO_MAXIMUM_SPEED}
|
||||
* if some roads have no speed limitation.
|
||||
*/
|
||||
public int getMaximumSpeed() {
|
||||
return this.maximumSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Maximum length of any arc in the graph.
|
||||
*/
|
||||
public float getMaximumLength() {
|
||||
return this.maximumLength;
|
||||
}
|
||||
|
||||
}
|
159
be-graphes-model/src/main/java/org/insa/graphs/model/Node.java
Normal file
159
be-graphes-model/src/main/java/org/insa/graphs/model/Node.java
Normal file
@@ -0,0 +1,159 @@
|
||||
package org.insa.graphs.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Class representing a Node in a {@link Graph}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This class holds information regarding nodes in the graph together with the
|
||||
* successors associated to the nodes.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Nodes are comparable based on their ID.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public final class Node implements Comparable<Node> {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Link the two given nodes with one or two arcs (depending on roadInformation),
|
||||
* with the given attributes.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If {@code roadInformation.isOneWay()} is {@code true}, only a forward arc is
|
||||
* created (origin to destination) and added to origin. Otherwise, a
|
||||
* corresponding backward arc is created and add to destination.
|
||||
* </p>
|
||||
*
|
||||
* @param origin Origin of the arc.
|
||||
* @param destination Destination of the arc.
|
||||
* @param length Length of the arc.
|
||||
* @param roadInformation Information corresponding to the arc.
|
||||
* @param points Points for the arc.
|
||||
*
|
||||
* @return The newly created forward arc (origin to destination).
|
||||
*/
|
||||
public static Arc linkNodes(Node origin, Node destination, float length,
|
||||
RoadInformation roadInformation, ArrayList<Point> points) {
|
||||
Arc arc = null;
|
||||
if (roadInformation.isOneWay()) {
|
||||
arc = new ArcForward(origin, destination, length, roadInformation, points);
|
||||
origin.addSuccessor(arc);
|
||||
}
|
||||
else {
|
||||
Arc d2o;
|
||||
if (origin.getId() < destination.getId()) {
|
||||
arc = new ArcForward(origin, destination, length, roadInformation, points);
|
||||
d2o = new ArcBackward(arc);
|
||||
}
|
||||
else {
|
||||
Collections.reverse(points);
|
||||
d2o = new ArcForward(destination, origin, length, roadInformation, points);
|
||||
arc = new ArcBackward(d2o);
|
||||
}
|
||||
origin.addSuccessor(arc);
|
||||
destination.addSuccessor(d2o);
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
||||
// ID of the node.
|
||||
private final int id;
|
||||
|
||||
// Point of this graph.
|
||||
private final Point point;
|
||||
|
||||
// Successors.
|
||||
private final ArrayList<Arc> successors;
|
||||
|
||||
/**
|
||||
* Create a new Node with the given ID corresponding to the given Point with an
|
||||
* empty list of successors.
|
||||
*
|
||||
* @param id ID of the node.
|
||||
* @param point Position of the node.
|
||||
*/
|
||||
public Node(int id, Point point) {
|
||||
this.id = id;
|
||||
this.point = point;
|
||||
this.successors = new ArrayList<Arc>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a successor to this node.
|
||||
*
|
||||
* @param arc Arc to the successor.
|
||||
*/
|
||||
protected void addSuccessor(Arc arc) {
|
||||
successors.add(arc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ID of this node.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Number of successors of this node.
|
||||
*/
|
||||
public int getNumberOfSuccessors() {
|
||||
return this.successors.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this node has at least one successor.
|
||||
*/
|
||||
public boolean hasSuccessors() {
|
||||
return !this.successors.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of successors of this node (unmodifiable list).
|
||||
*
|
||||
* @see Collections#unmodifiableList(List)
|
||||
*/
|
||||
public List<Arc> getSuccessors() {
|
||||
return Collections.unmodifiableList(this.successors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Location of this node.
|
||||
*/
|
||||
public Point getPoint() {
|
||||
return point;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
if (other instanceof Node) {
|
||||
return getId() == ((Node) other).getId();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the ID of this node with the ID of the given node.
|
||||
*
|
||||
* @param other Node to compare this node with.
|
||||
*
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(Node other) {
|
||||
return Integer.compare(getId(), other.getId());
|
||||
}
|
||||
|
||||
}
|
248
be-graphes-model/src/main/java/org/insa/graphs/model/Path.java
Normal file
248
be-graphes-model/src/main/java/org/insa/graphs/model/Path.java
Normal file
@@ -0,0 +1,248 @@
|
||||
package org.insa.graphs.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Class representing a path between nodes in a graph.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A path is represented as a list of {@link Arc} with an origin and not a list
|
||||
* of {@link Node} due to the multi-graph nature (multiple arcs between two
|
||||
* nodes) of the considered graphs.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public class Path {
|
||||
|
||||
/**
|
||||
* Create a new path that goes through the given list of nodes (in order),
|
||||
* choosing the fastest route if multiple are available.
|
||||
*
|
||||
* @param graph Graph containing the nodes in the list.
|
||||
* @param nodes List of nodes to build the path.
|
||||
*
|
||||
* @return A path that goes through the given list of nodes.
|
||||
*
|
||||
* @throws IllegalArgumentException If the list of nodes is not valid, i.e. two
|
||||
* consecutive nodes in the list are not connected in the graph.
|
||||
*
|
||||
* @deprecated Need to be implemented.
|
||||
*/
|
||||
public static Path createFastestPathFromNodes(Graph graph, List<Node> nodes)
|
||||
throws IllegalArgumentException {
|
||||
List<Arc> arcs = new ArrayList<Arc>();
|
||||
// TODO:
|
||||
return new Path(graph, arcs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new path that goes through the given list of nodes (in order),
|
||||
* choosing the shortest route if multiple are available.
|
||||
*
|
||||
* @param graph Graph containing the nodes in the list.
|
||||
* @param nodes List of nodes to build the path.
|
||||
*
|
||||
* @return A path that goes through the given list of nodes.
|
||||
*
|
||||
* @throws IllegalArgumentException If the list of nodes is not valid, i.e. two
|
||||
* consecutive nodes in the list are not connected in the graph.
|
||||
*
|
||||
* @deprecated Need to be implemented.
|
||||
*/
|
||||
public static Path createShortestPathFromNodes(Graph graph, List<Node> nodes)
|
||||
throws IllegalArgumentException {
|
||||
List<Arc> arcs = new ArrayList<Arc>();
|
||||
// TODO:
|
||||
return new Path(graph, arcs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate the given paths.
|
||||
*
|
||||
* @param paths Array of paths to concatenate.
|
||||
*
|
||||
* @return Concatenated path.
|
||||
*
|
||||
* @throws IllegalArgumentException if the paths cannot be concatenated (IDs of
|
||||
* map do not match, or the end of a path is not the beginning of the
|
||||
* next).
|
||||
*/
|
||||
public static Path concatenate(Path... paths) throws IllegalArgumentException {
|
||||
if (paths.length == 0) {
|
||||
throw new IllegalArgumentException("Cannot concatenate an empty list of paths.");
|
||||
}
|
||||
final String mapId = paths[0].getGraph().getMapId();
|
||||
for (int i = 1; i < paths.length; ++i) {
|
||||
if (!paths[i].getGraph().getMapId().equals(mapId)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot concatenate paths from different graphs.");
|
||||
}
|
||||
}
|
||||
ArrayList<Arc> arcs = new ArrayList<>();
|
||||
for (Path path: paths) {
|
||||
arcs.addAll(path.getArcs());
|
||||
}
|
||||
Path path = new Path(paths[0].getGraph(), arcs);
|
||||
if (!path.isValid()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot concatenate paths that do not form a single path.");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// Graph containing this path.
|
||||
private final Graph graph;
|
||||
|
||||
// Origin of the path
|
||||
private final Node origin;
|
||||
|
||||
// List of arcs in this path.
|
||||
private final List<Arc> arcs;
|
||||
|
||||
/**
|
||||
* Create an empty path corresponding to the given graph.
|
||||
*
|
||||
* @param graph Graph containing the path.
|
||||
*/
|
||||
public Path(Graph graph) {
|
||||
this.graph = graph;
|
||||
this.origin = null;
|
||||
this.arcs = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new path containing a single node.
|
||||
*
|
||||
* @param graph Graph containing the path.
|
||||
* @param node Single node of the path.
|
||||
*/
|
||||
public Path(Graph graph, Node node) {
|
||||
this.graph = graph;
|
||||
this.origin = node;
|
||||
this.arcs = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new path with the given list of arcs.
|
||||
*
|
||||
* @param graph Graph containing the path.
|
||||
* @param arcs Arcs to construct the path.
|
||||
*/
|
||||
public Path(Graph graph, List<Arc> arcs) {
|
||||
this.graph = graph;
|
||||
this.arcs = arcs;
|
||||
this.origin = arcs.size() > 0 ? arcs.get(0).getOrigin() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Graph containing the path.
|
||||
*/
|
||||
public Graph getGraph() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return First node of the path.
|
||||
*/
|
||||
public Node getOrigin() {
|
||||
return origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Last node of the path.
|
||||
*/
|
||||
public Node getDestination() {
|
||||
return arcs.get(arcs.size() - 1).getDestination();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of arcs in the path.
|
||||
*/
|
||||
public List<Arc> getArcs() {
|
||||
return Collections.unmodifiableList(arcs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this path is empty (it does not contain any node).
|
||||
*
|
||||
* @return true if this path is empty, false otherwise.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return this.origin == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of <b>nodes</b> in this path.
|
||||
*
|
||||
* @return Number of nodes in this path.
|
||||
*/
|
||||
public int size() {
|
||||
return isEmpty() ? 0 : 1 + this.arcs.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this path is valid.
|
||||
*
|
||||
* A path is valid if any of the following is true:
|
||||
* <ul>
|
||||
* <li>it is empty;</li>
|
||||
* <li>it contains a single node (without arcs);</li>
|
||||
* <li>the first arc has for origin the origin of the path and, for two
|
||||
* consecutive arcs, the destination of the first one is the origin of the
|
||||
* second one.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return true if the path is valid, false otherwise.
|
||||
*
|
||||
* @deprecated Need to be implemented.
|
||||
*/
|
||||
public boolean isValid() {
|
||||
// TODO:
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the length of this path (in meters).
|
||||
*
|
||||
* @return Total length of the path (in meters).
|
||||
*
|
||||
* @deprecated Need to be implemented.
|
||||
*/
|
||||
public float getLength() {
|
||||
// TODO:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the time required to travel this path if moving at the given speed.
|
||||
*
|
||||
* @param speed Speed to compute the travel time.
|
||||
*
|
||||
* @return Time (in seconds) required to travel this path at the given speed (in
|
||||
* kilometers-per-hour).
|
||||
*
|
||||
* @deprecated Need to be implemented.
|
||||
*/
|
||||
public double getTravelTime(double speed) {
|
||||
// TODO:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the time to travel this path if moving at the maximum allowed speed
|
||||
* on every arc.
|
||||
*
|
||||
* @return Minimum travel time to travel this path (in seconds).
|
||||
*
|
||||
* @deprecated Need to be implemented.
|
||||
*/
|
||||
public double getMinimumTravelTime() {
|
||||
// TODO:
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
package org.insa.graphs.model;
|
||||
|
||||
/**
|
||||
* Class representing a point (position) on Earth.
|
||||
*
|
||||
*/
|
||||
public final class Point {
|
||||
|
||||
/**
|
||||
* Approximated Earth radius (in meters).
|
||||
*/
|
||||
public static final double EARTH_RADIUS = 6378137.0;
|
||||
|
||||
/**
|
||||
* Compute the distance in meters between the two given points.
|
||||
*
|
||||
* @param p1 First point.
|
||||
* @param p2 second point.
|
||||
*
|
||||
* @return Distance between the two given points (in meters).
|
||||
*/
|
||||
public static double distance(Point p1, Point p2) {
|
||||
double sinLat = Math.sin(Math.toRadians(p1.getLatitude()))
|
||||
* Math.sin(Math.toRadians(p2.getLatitude()));
|
||||
double cosLat = Math.cos(Math.toRadians(p1.getLatitude()))
|
||||
* Math.cos(Math.toRadians(p2.getLatitude()));
|
||||
double cosLong = Math.cos(Math.toRadians(p2.getLongitude() - p1.getLongitude()));
|
||||
return EARTH_RADIUS * Math.acos(sinLat + cosLat * cosLong);
|
||||
}
|
||||
|
||||
// Longitude and latitude of the point.
|
||||
private final float longitude, latitude;
|
||||
|
||||
/**
|
||||
* Create a new point corresponding to the given (longitude, latitude) position.
|
||||
*
|
||||
* @param longitude Longitude of the point (in degrees).
|
||||
* @param latitude Latitude of the point (in degrees).
|
||||
*/
|
||||
public Point(float longitude, float latitude) {
|
||||
this.longitude = longitude;
|
||||
this.latitude = latitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Longitude of this point (in degrees).
|
||||
*/
|
||||
public float getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Latitude of this point (in degrees).
|
||||
*/
|
||||
public float getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the distance from this point to the given point
|
||||
*
|
||||
* @param target Target point to compute distance to.
|
||||
*
|
||||
* @return Distance between this point and the target point, in meters.
|
||||
*/
|
||||
public double distanceTo(Point target) {
|
||||
return distance(this, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Point(%f, %f)", getLongitude(), getLatitude());
|
||||
}
|
||||
}
|
@@ -0,0 +1,126 @@
|
||||
package org.insa.graphs.model;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Class containing information for road that may be shared by multiple arcs.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Sharing information between arcs reduces memory footprints of the program (a
|
||||
* long road is often split into multiple arcs at each intersection).
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public class RoadInformation {
|
||||
|
||||
/**
|
||||
* Enumeration for road types.
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://wiki.openstreetmap.org/wiki/Key:highway#Values">OpenStreetMap
|
||||
* reference for road types.</a>
|
||||
*/
|
||||
public enum RoadType {
|
||||
MOTORWAY,
|
||||
TRUNK,
|
||||
PRIMARY,
|
||||
SECONDARY,
|
||||
MOTORWAY_LINK,
|
||||
TRUNK_LINK,
|
||||
PRIMARY_LINK,
|
||||
SECONDARY_LINK,
|
||||
TERTIARY,
|
||||
TRACK,
|
||||
RESIDENTIAL,
|
||||
UNCLASSIFIED,
|
||||
LIVING_STREET,
|
||||
SERVICE,
|
||||
ROUNDABOUT,
|
||||
PEDESTRIAN,
|
||||
CYCLEWAY,
|
||||
COASTLINE
|
||||
}
|
||||
|
||||
// Type of the road (see above).
|
||||
private final RoadType type;
|
||||
|
||||
// Access information
|
||||
private final AccessRestrictions access;
|
||||
|
||||
// One way road?
|
||||
private final boolean oneway;
|
||||
|
||||
// Max speed in kilometers per hour.
|
||||
private final int maxSpeed;
|
||||
|
||||
// Name of the road.
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Create a new RoadInformation instance containing the given parameters.
|
||||
*
|
||||
* @param roadType Type of the road (see {@link RoadType}).
|
||||
* @param access Access restrictions for the road (see
|
||||
* {@link AccessRestrictions}).
|
||||
* @param isOneWay true if this road is a one way road, false otherwise.
|
||||
* @param maxSpeed Maximum speed for the road (in kilometers-per-hour).
|
||||
* @param name Name of the road.
|
||||
*/
|
||||
public RoadInformation(RoadType roadType, AccessRestrictions access, boolean isOneWay,
|
||||
int maxSpeed, String name) {
|
||||
this.type = roadType;
|
||||
this.access = access;
|
||||
this.oneway = isOneWay;
|
||||
this.maxSpeed = maxSpeed;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Access restrictions for this road.
|
||||
*/
|
||||
public AccessRestrictions getAccessRestrictions() {
|
||||
return this.access;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Type of the road.
|
||||
*/
|
||||
public RoadType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the road is a one-way road.
|
||||
*/
|
||||
public boolean isOneWay() {
|
||||
return oneway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Maximum speed for this road (in kilometers-per-hour).
|
||||
*/
|
||||
public int getMaximumSpeed() {
|
||||
return maxSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Name of the road.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String typeAsString = "road";
|
||||
if (getType() == RoadType.COASTLINE) {
|
||||
typeAsString = "coast";
|
||||
}
|
||||
if (getType() == RoadType.MOTORWAY) {
|
||||
typeAsString = "highway";
|
||||
}
|
||||
return typeAsString + " : " + getName() + " " + (isOneWay() ? " (oneway) " : "") + maxSpeed
|
||||
+ " km/h (max.)";
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Exception thrown when a format-error is detected when reading a graph (e.g.,
|
||||
* non-matching check bytes).
|
||||
*
|
||||
*/
|
||||
public class BadFormatException extends IOException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public BadFormatException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new format exception with the given message.
|
||||
*
|
||||
* @param message Message for the exception.
|
||||
*/
|
||||
public BadFormatException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
/**
|
||||
* Exception thrown when there is a mismatch between expected and actual magic
|
||||
* number.
|
||||
*
|
||||
*/
|
||||
public class BadMagicNumberException extends BadFormatException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -2176603967548838864L;
|
||||
|
||||
// Actual and expected magic numbers.
|
||||
private int actualNumber, expectedNumber;
|
||||
|
||||
/**
|
||||
* Create a new BadMagicNumberException with the given expected and actual magic
|
||||
* number.
|
||||
*
|
||||
* @param actualNumber Actual magic number (read from a file).
|
||||
* @param expectedNumber Expected magic number.
|
||||
*/
|
||||
public BadMagicNumberException(int actualNumber, int expectedNumber) {
|
||||
super(String.format("Magic number mismatch, expected %#X, got %#X.", expectedNumber,
|
||||
actualNumber));
|
||||
this.actualNumber = actualNumber;
|
||||
this.expectedNumber = expectedNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The actual magic number.
|
||||
*/
|
||||
public int getActualMagicNumber() {
|
||||
return actualNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The expected magic number.
|
||||
*/
|
||||
public int getExpectedMagicNumber() {
|
||||
return expectedNumber;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
/**
|
||||
* Exception thrown when the version of the file is not at least the expected
|
||||
* one.
|
||||
*
|
||||
*/
|
||||
public class BadVersionException extends BadFormatException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 7776317018302386042L;
|
||||
|
||||
// Actual and expected version..
|
||||
private int actualVersion, expectedVersion;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param actualVersion Actual version of the file.
|
||||
* @param expectedVersion Expected version of the file.
|
||||
*/
|
||||
public BadVersionException(int actualVersion, int expectedVersion) {
|
||||
super();
|
||||
this.actualVersion = actualVersion;
|
||||
this.expectedVersion = expectedVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Actual version of the file.
|
||||
*/
|
||||
public int getActualVersion() {
|
||||
return actualVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Expected (minimal) version of the file.
|
||||
*/
|
||||
public int getExpectedVersion() {
|
||||
return expectedVersion;
|
||||
}
|
||||
}
|
@@ -0,0 +1,323 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.insa.graphs.model.AccessRestrictions;
|
||||
import org.insa.graphs.model.Arc;
|
||||
import org.insa.graphs.model.Graph;
|
||||
import org.insa.graphs.model.GraphStatistics;
|
||||
import org.insa.graphs.model.Node;
|
||||
import org.insa.graphs.model.Point;
|
||||
import org.insa.graphs.model.RoadInformation;
|
||||
import org.insa.graphs.model.AccessRestrictions.AccessMode;
|
||||
import org.insa.graphs.model.AccessRestrictions.AccessRestriction;
|
||||
import org.insa.graphs.model.GraphStatistics.BoundingBox;
|
||||
import org.insa.graphs.model.RoadInformation.RoadType;
|
||||
|
||||
/**
|
||||
* Implementation of {@link GraphReader} to read graph in binary format.
|
||||
*
|
||||
*/
|
||||
public class BinaryGraphReader extends BinaryReader implements GraphReader {
|
||||
|
||||
// Map version and magic number targeted for this reader.
|
||||
private static final int VERSION = 5;
|
||||
private static final int MAGIC_NUMBER = 0x208BC3B3;
|
||||
|
||||
// Length of the map id field (in bytes)
|
||||
protected static final int MAP_ID_FIELD_LENGTH = 32;
|
||||
|
||||
// List of observers
|
||||
protected List<GraphReaderObserver> observers = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Parse the given long value into a new instance of AccessRestrictions.
|
||||
*
|
||||
* @param access The value to parse.
|
||||
*
|
||||
* @return New instance of access restrictions parsed from the given value.
|
||||
*/
|
||||
protected static AccessRestrictions toAccessInformation(final long access) {
|
||||
|
||||
// See the following for more information:
|
||||
// https://github.com/Holt59/OSM2Graph/blob/master/src/main/org/laas/osm2graph/model/AccessData.java
|
||||
|
||||
// The order of values inside this array is VERY IMPORTANT: For allRestrictions,
|
||||
// the order correspond to the 4 bits value (i.e. FORBIDDEN is 0 or PRIVATE is
|
||||
// 2) - UKNOWN is not included because value above 6 (FORESTRY) are all
|
||||
// considered unknown.
|
||||
final AccessRestriction[] allRestrictions = new AccessRestriction[] {
|
||||
AccessRestriction.FORBIDDEN, AccessRestriction.ALLOWED, AccessRestriction.PRIVATE,
|
||||
AccessRestriction.DESTINATION, AccessRestriction.DELIVERY,
|
||||
AccessRestriction.CUSTOMERS, AccessRestriction.FORESTRY };
|
||||
|
||||
// The order of values inside this array is VERY IMPORTANT: The order is such
|
||||
// that each 4-bits group of the long value is processed in the correct order,
|
||||
// i.e. FOOT is processed first (4 lowest bits), and so on.
|
||||
final AccessMode[] allModes = new AccessMode[] { AccessMode.FOOT, null, AccessMode.BICYCLE,
|
||||
AccessMode.SMALL_MOTORCYCLE, AccessMode.AGRICULTURAL, AccessMode.MOTORCYCLE,
|
||||
AccessMode.MOTORCAR, AccessMode.HEAVY_GOODS, null, AccessMode.PUBLIC_TRANSPORT };
|
||||
|
||||
// fill maps...
|
||||
EnumMap<AccessMode, AccessRestriction> restrictions = new EnumMap<>(AccessMode.class);
|
||||
long copyAccess = access;
|
||||
for (AccessMode mode: allModes) {
|
||||
if (mode == null) {
|
||||
continue; // filling cells
|
||||
}
|
||||
int value = (int) (copyAccess & 0xf);
|
||||
if (value < allRestrictions.length) {
|
||||
restrictions.put(mode, allRestrictions[value]);
|
||||
}
|
||||
else {
|
||||
restrictions.put(mode, AccessRestriction.UNKNOWN);
|
||||
}
|
||||
copyAccess = copyAccess >> 4;
|
||||
}
|
||||
|
||||
return new AccessRestrictions(restrictions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a character to its corresponding road type.
|
||||
*
|
||||
* @param ch Character to convert.
|
||||
*
|
||||
* @return Road type corresponding to the given character.
|
||||
*
|
||||
*/
|
||||
protected 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':
|
||||
case 'l':
|
||||
return RoadType.UNCLASSIFIED;
|
||||
case 'm':
|
||||
return RoadType.LIVING_STREET;
|
||||
case 'n':
|
||||
return RoadType.SERVICE;
|
||||
case 'o':
|
||||
return RoadType.ROUNDABOUT;
|
||||
case 'p':
|
||||
return RoadType.PEDESTRIAN;
|
||||
case 'r':
|
||||
return RoadType.CYCLEWAY;
|
||||
case 's':
|
||||
return RoadType.TRACK;
|
||||
case 'z':
|
||||
return RoadType.COASTLINE;
|
||||
}
|
||||
return RoadType.UNCLASSIFIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new BinaryGraphReader that read from the given input stream.
|
||||
*
|
||||
* @param dis Input stream to read from.
|
||||
*/
|
||||
public BinaryGraphReader(DataInputStream dis) {
|
||||
super(MAGIC_NUMBER, VERSION, dis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addObserver(GraphReaderObserver observer) {
|
||||
observers.add(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph read() throws IOException {
|
||||
|
||||
// Read and check magic number and file version.
|
||||
checkMagicNumberOrThrow(dis.readInt());
|
||||
checkVersionOrThrow(dis.readInt());
|
||||
|
||||
// Read map id.
|
||||
String mapId;
|
||||
String mapName = "";
|
||||
|
||||
if (getCurrentVersion() < 6) {
|
||||
mapId = "0x" + Integer.toHexString(dis.readInt());
|
||||
}
|
||||
else {
|
||||
mapId = readFixedLengthString(MAP_ID_FIELD_LENGTH, "UTF-8");
|
||||
mapName = dis.readUTF();
|
||||
}
|
||||
|
||||
observers.forEach((observer) -> observer.notifyStartReading(mapId));
|
||||
|
||||
// Number of descriptors and nodes.
|
||||
int nbDesc = dis.readInt();
|
||||
int nbNodes = dis.readInt();
|
||||
|
||||
// Number of successors for each nodes.
|
||||
int[] nbSuccessors = new int[nbNodes];
|
||||
int nbTotalSuccessors = 0;
|
||||
|
||||
// Construct an array list with initial capacity of nbNodes.
|
||||
ArrayList<Node> nodes = new ArrayList<Node>(nbNodes);
|
||||
|
||||
// Read nodes.
|
||||
float minLongitude = Float.POSITIVE_INFINITY, minLatitude = Float.POSITIVE_INFINITY,
|
||||
maxLongitude = Float.NEGATIVE_INFINITY, maxLatitude = Float.NEGATIVE_INFINITY;
|
||||
observers.forEach((observer) -> observer.notifyStartReadingNodes(nbNodes));
|
||||
for (int node = 0; node < nbNodes; ++node) {
|
||||
// Read longitude / latitude.
|
||||
float longitude = ((float) dis.readInt()) / 1E6f;
|
||||
float latitude = ((float) dis.readInt()) / 1E6f;
|
||||
|
||||
// Update minimum / maximum.
|
||||
minLongitude = Math.min(longitude, minLongitude);
|
||||
minLatitude = Math.min(latitude, minLatitude);
|
||||
maxLongitude = Math.max(longitude, maxLongitude);
|
||||
maxLatitude = Math.max(latitude, maxLatitude);
|
||||
|
||||
// Update information.
|
||||
nbSuccessors[node] = dis.readUnsignedByte();
|
||||
nbTotalSuccessors += nbSuccessors[node];
|
||||
|
||||
// Create node.
|
||||
final Node aNode = new Node(node, new Point(longitude, latitude));
|
||||
nodes.add(aNode);
|
||||
observers.forEach((observer) -> observer.notifyNewNodeRead(aNode));
|
||||
}
|
||||
|
||||
// Check format.
|
||||
checkByteOrThrow(255);
|
||||
|
||||
// Read descriptors.
|
||||
RoadInformation[] descs = new RoadInformation[nbDesc];
|
||||
|
||||
// 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.
|
||||
float maxLength = 0;
|
||||
final int copyNbTotalSuccesors = nbTotalSuccessors; // Stupid Java...
|
||||
int nbOneWayRoad = 0;
|
||||
observers.forEach((observer) -> observer.notifyStartReadingArcs(copyNbTotalSuccesors));
|
||||
for (int node = 0; node < nbNodes; ++node) {
|
||||
for (int succ = 0; succ < nbSuccessors[node]; ++succ) {
|
||||
|
||||
// Read target node number.
|
||||
int destNode = this.read24bits();
|
||||
|
||||
// Read information number.
|
||||
int descrNum = this.read24bits();
|
||||
|
||||
// Length of the arc.
|
||||
float length;
|
||||
if (getCurrentVersion() < 8) {
|
||||
length = dis.readUnsignedShort();
|
||||
}
|
||||
else {
|
||||
length = dis.readInt() / 1000.0f;
|
||||
}
|
||||
maxLength = Math.max(length, maxLength);
|
||||
|
||||
length = Math.max(length, (float) Point.distance(nodes.get(node).getPoint(),
|
||||
nodes.get(destNode).getPoint()));
|
||||
|
||||
// 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());
|
||||
|
||||
RoadInformation info = descs[descrNum];
|
||||
Node orig = nodes.get(node);
|
||||
Node dest = nodes.get(destNode);
|
||||
|
||||
// Add successor to initial arc.
|
||||
Arc arc = Node.linkNodes(orig, dest, length, info, points);
|
||||
if (info.isOneWay()) {
|
||||
nbOneWayRoad++;
|
||||
}
|
||||
observers.forEach((observer) -> observer.notifyNewArcRead(arc));
|
||||
}
|
||||
}
|
||||
|
||||
// Check format.
|
||||
checkByteOrThrow(253);
|
||||
|
||||
observers.forEach((observer) -> observer.notifyEndReading());
|
||||
|
||||
this.dis.close();
|
||||
|
||||
return new Graph(mapId, mapName, nodes,
|
||||
new GraphStatistics(
|
||||
new BoundingBox(new Point(minLongitude, maxLatitude),
|
||||
new Point(maxLongitude, minLatitude)),
|
||||
nbOneWayRoad, nbTotalSuccessors - nbOneWayRoad, maxSpeed, maxLength));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the next road information from the stream.
|
||||
*
|
||||
* @return The next RoadInformation in the stream.
|
||||
*
|
||||
* @throws IOException if an error occurs while reading from the stream.
|
||||
*/
|
||||
private RoadInformation readRoadInformation() throws IOException {
|
||||
char type = (char) dis.readUnsignedByte();
|
||||
int x = dis.readUnsignedByte();
|
||||
AccessRestrictions access = new AccessRestrictions();
|
||||
if (getCurrentVersion() >= 7) {
|
||||
access = toAccessInformation(dis.readLong());
|
||||
}
|
||||
else if (getCurrentVersion() >= 6) {
|
||||
// TODO: Try to create something...
|
||||
dis.readUnsignedShort();
|
||||
}
|
||||
return new RoadInformation(toRoadType(type), access, (x & 0x80) > 0, (x & 0x7F) * 5,
|
||||
dis.readUTF());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.insa.graphs.model.Graph;
|
||||
import org.insa.graphs.model.Node;
|
||||
import org.insa.graphs.model.Path;
|
||||
|
||||
/**
|
||||
* Implementation of {@link PathReader} to read paths in binary format.
|
||||
*
|
||||
*/
|
||||
public class BinaryPathReader extends BinaryReader implements PathReader {
|
||||
|
||||
// Map version and magic number targeted for this reader.
|
||||
protected static final int VERSION = 1;
|
||||
protected static final int MAGIC_NUMBER = 0xdecafe;
|
||||
|
||||
/**
|
||||
* Create a new BinaryPathReader that read from the given input stream.
|
||||
*
|
||||
* @param dis Input stream to read from.
|
||||
*/
|
||||
public BinaryPathReader(DataInputStream dis) {
|
||||
super(MAGIC_NUMBER, VERSION, dis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path readPath(Graph graph) throws IOException {
|
||||
|
||||
// Read and check magic number and version.
|
||||
checkMagicNumberOrThrow(dis.readInt());
|
||||
checkVersionOrThrow(dis.readInt());
|
||||
|
||||
// Read map ID and check against graph.
|
||||
String mapId = readFixedLengthString(BinaryGraphReader.MAP_ID_FIELD_LENGTH, "UTF-8");
|
||||
|
||||
if (!mapId.equals(graph.getMapId())) {
|
||||
throw new MapMismatchException(mapId, graph.getMapId());
|
||||
}
|
||||
|
||||
// Number of nodes in the path (without first and last).
|
||||
int nbNodes = dis.readInt();
|
||||
|
||||
// Skip (duplicate) first and last node
|
||||
readNode(graph);
|
||||
readNode(graph);
|
||||
|
||||
// Read intermediate nodes:
|
||||
ArrayList<Node> nodes = new ArrayList<Node>();
|
||||
for (int i = 0; i < nbNodes; ++i) {
|
||||
nodes.add(readNode(graph));
|
||||
}
|
||||
|
||||
this.dis.close();
|
||||
|
||||
return Path.createFastestPathFromNodes(graph, nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a node from the input stream and returns it.
|
||||
*
|
||||
* @param graph Graph containing the nodes.
|
||||
*
|
||||
* @return The next node in the input stream.
|
||||
*
|
||||
* @throws IOException if something occurs while reading the note.
|
||||
* @throws IndexOutOfBoundsException if the node is not in the graph.
|
||||
*/
|
||||
protected Node readNode(Graph graph) throws IOException {
|
||||
return graph.get(dis.readInt());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.insa.graphs.model.Arc;
|
||||
import org.insa.graphs.model.Path;
|
||||
|
||||
/**
|
||||
* Implementation of {@link PathWriter} to write paths in binary format.
|
||||
*
|
||||
*/
|
||||
public class BinaryPathWriter extends BinaryWriter implements PathWriter {
|
||||
|
||||
/**
|
||||
* Create a new BinaryPathWriter that writes to the given output stream.
|
||||
*
|
||||
* @param dos Output stream to write to.
|
||||
*/
|
||||
public BinaryPathWriter(DataOutputStream dos) {
|
||||
super(dos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writePath(Path path) throws IOException {
|
||||
|
||||
// Write magic number and version.
|
||||
dos.writeInt(BinaryPathReader.MAGIC_NUMBER);
|
||||
dos.writeInt(BinaryPathReader.VERSION);
|
||||
|
||||
// Write map id.
|
||||
byte[] bytes = Arrays.copyOf(path.getGraph().getMapId().getBytes("UTF-8"),
|
||||
BinaryGraphReader.MAP_ID_FIELD_LENGTH);
|
||||
dos.write(bytes);
|
||||
|
||||
// Write number of arcs
|
||||
dos.writeInt(path.getArcs().size() + 1);
|
||||
|
||||
// Write origin / destination.
|
||||
dos.writeInt(path.getOrigin().getId());
|
||||
dos.writeInt(path.getDestination().getId());
|
||||
|
||||
// Write nodes.
|
||||
dos.writeInt(path.getOrigin().getId());
|
||||
for (Arc arc: path.getArcs()) {
|
||||
dos.writeInt(arc.getDestination().getId());
|
||||
}
|
||||
|
||||
dos.flush();
|
||||
dos.close();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,121 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Base class for writing binary file.
|
||||
*
|
||||
*/
|
||||
public abstract class BinaryReader implements AutoCloseable, Closeable {
|
||||
|
||||
// Map version and magic number targeted for this reader.
|
||||
private final int minVersion;
|
||||
private int curVersion;
|
||||
private final int magicNumber;
|
||||
|
||||
// InputStream
|
||||
protected final DataInputStream dis;
|
||||
|
||||
/**
|
||||
* Create a new BinaryReader that reads from the given stream and that expected
|
||||
* the given magic number and at least the given minimum version.
|
||||
*
|
||||
* @param magicNumber Magic number of files to be read.
|
||||
* @param minVersion Minimum version of files to be read.
|
||||
* @param dis Input stream from which to read.
|
||||
*/
|
||||
protected BinaryReader(int magicNumber, int minVersion, DataInputStream dis) {
|
||||
this.magicNumber = magicNumber;
|
||||
this.minVersion = minVersion;
|
||||
this.dis = dis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.dis.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given version is greater than the minimum version, and update
|
||||
* the current version if it is.
|
||||
*
|
||||
* @param version Version to check.
|
||||
*
|
||||
* @throws BadVersionException if the given version is not greater than the
|
||||
* minimum version.
|
||||
*/
|
||||
protected void checkVersionOrThrow(int version) throws BadVersionException {
|
||||
if (version < this.minVersion) {
|
||||
throw new BadVersionException(version, this.minVersion);
|
||||
}
|
||||
this.curVersion = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The current version.
|
||||
*/
|
||||
protected int getCurrentVersion() {
|
||||
return this.curVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given number matches the expected magic number.
|
||||
*
|
||||
* @param magicNumber The magic number to check.
|
||||
*
|
||||
* @throws BadMagicNumberException If the two magic numbers are not equal.
|
||||
*/
|
||||
protected void checkMagicNumberOrThrow(int magicNumber) throws BadMagicNumberException {
|
||||
if (this.magicNumber != magicNumber) {
|
||||
throw new BadMagicNumberException(magicNumber, this.magicNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the next byte in the input stream correspond to the given byte.
|
||||
*
|
||||
* This function consumes the next byte in the input stream.
|
||||
*
|
||||
* @param b Byte to check.
|
||||
*
|
||||
* @throws IOException if an error occurs while reading the byte.
|
||||
* @throws BadFormatException if the byte read is not the expected one.
|
||||
*/
|
||||
protected void checkByteOrThrow(int b) throws IOException {
|
||||
if (dis.readUnsignedByte() != b) {
|
||||
throw new BadFormatException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte array of fixed length from the input and convert it to a string
|
||||
* using the given charset, removing any trailing '\0'.
|
||||
*
|
||||
* @param length Number of bytes to read.
|
||||
* @param charset Charset to use to convert the bytes into a string.
|
||||
*
|
||||
* @return The convert string.
|
||||
*
|
||||
* @throws IOException if an error occurs while reading or converting.
|
||||
*/
|
||||
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 in BigEndian order from the stream and return the corresponding
|
||||
* integer value.
|
||||
*
|
||||
* @return Integer value read from the next 24 bits of the stream.
|
||||
*
|
||||
* @throws IOException if an error occurs while reading from the stream.
|
||||
*/
|
||||
protected int read24bits() throws IOException {
|
||||
int x = dis.readUnsignedShort();
|
||||
return (x << 8) | dis.readUnsignedByte();
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Base class for writing binary file.
|
||||
*
|
||||
*/
|
||||
public abstract class BinaryWriter implements AutoCloseable, Closeable {
|
||||
|
||||
// Output stream.
|
||||
protected final DataOutputStream dos;
|
||||
|
||||
/**
|
||||
* Create a new BinaryWriter that writes to the given output stream.
|
||||
*
|
||||
* @param dos Stream to write to.
|
||||
*/
|
||||
protected BinaryWriter(DataOutputStream dos) {
|
||||
this.dos = dos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
this.dos.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 24-bits integer in BigEndian order to the output stream.
|
||||
*
|
||||
* @param value Value to write.
|
||||
*
|
||||
* @throws IOException if an error occurs while writing to the stream.
|
||||
*/
|
||||
protected void write24bits(int value) throws IOException {
|
||||
dos.writeShort(value >> 8);
|
||||
dos.writeByte(value & 0xff);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.insa.graphs.model.Graph;
|
||||
|
||||
/**
|
||||
* Base interface for classes that can read graph.
|
||||
*
|
||||
*/
|
||||
public interface GraphReader extends AutoCloseable, Closeable {
|
||||
|
||||
/**
|
||||
* Add a new observer to this graph reader.
|
||||
*
|
||||
* @param observer Observer to add.
|
||||
*/
|
||||
public void addObserver(GraphReaderObserver observer);
|
||||
|
||||
/**
|
||||
* Read a graph an returns it.
|
||||
*
|
||||
* @return The graph read.
|
||||
*
|
||||
* @throws IOException if an exception occurs while reading the graph.
|
||||
*
|
||||
*/
|
||||
public Graph read() throws IOException;
|
||||
|
||||
/**
|
||||
* Close this graph reader.
|
||||
*
|
||||
* @throws IOException if an exception occurs while closing the reader.
|
||||
*
|
||||
*/
|
||||
public void close() throws IOException;
|
||||
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
import org.insa.graphs.model.Arc;
|
||||
import org.insa.graphs.model.Node;
|
||||
import org.insa.graphs.model.RoadInformation;
|
||||
|
||||
/**
|
||||
* Base interface that should be implemented by classes that want to observe the
|
||||
* reading of a graph by a {@link GraphReader}.
|
||||
*
|
||||
*/
|
||||
public interface GraphReaderObserver {
|
||||
|
||||
/**
|
||||
* Notify observer about information on the graph, this method is always the
|
||||
* first called
|
||||
*
|
||||
* @param mapId ID of the graph.
|
||||
*/
|
||||
public void notifyStartReading(String mapId);
|
||||
|
||||
/**
|
||||
* Notify that the graph has been fully read.
|
||||
*/
|
||||
public void notifyEndReading();
|
||||
|
||||
/**
|
||||
* Notify that the reader is starting to read node.
|
||||
*
|
||||
* @param nNodes Number of nodes to read.
|
||||
*/
|
||||
public void notifyStartReadingNodes(int nNodes);
|
||||
|
||||
/**
|
||||
* Notify that a new nodes has been read.
|
||||
*
|
||||
* @param node read.
|
||||
*/
|
||||
public void notifyNewNodeRead(Node node);
|
||||
|
||||
/**
|
||||
* Notify that the reader is starting to read descriptor/road informations.
|
||||
*
|
||||
* @param nDesc Number of descriptors to read.
|
||||
*/
|
||||
public void notifyStartReadingDescriptors(int nDesc);
|
||||
|
||||
/**
|
||||
* Notify that a new descriptor has been read.
|
||||
*
|
||||
* @param desc Descriptor read.
|
||||
*/
|
||||
public void notifyNewDescriptorRead(RoadInformation desc);
|
||||
|
||||
/**
|
||||
* Notify that the reader is starting to read arcs.
|
||||
*
|
||||
* @param nArcs Number of arcs to read (!= number of arcs in the graph).
|
||||
*/
|
||||
public void notifyStartReadingArcs(int nArcs);
|
||||
|
||||
/**
|
||||
* Notify that a new arc has been read.
|
||||
*
|
||||
* @param arc Arc read.
|
||||
*/
|
||||
public void notifyNewArcRead(Arc arc);
|
||||
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Exception thrown when there is mismatch between the expected map ID and the
|
||||
* actual map ID when reading a graph.
|
||||
*
|
||||
*/
|
||||
public class MapMismatchException extends IOException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// Actual and expected map ID.
|
||||
private String actualMapId, expectedMapId;
|
||||
|
||||
/**
|
||||
* Create a new MapMismatchException with the given IDs.
|
||||
*
|
||||
* @param actualMapId Actual map ID found when reading the path.
|
||||
* @param expectedMapId Expected map ID from the graph.
|
||||
*/
|
||||
public MapMismatchException(String actualMapId, String expectedMapId) {
|
||||
super();
|
||||
this.actualMapId = actualMapId;
|
||||
this.expectedMapId = expectedMapId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Actual ID of the map (read from the path).
|
||||
*/
|
||||
public String getActualMapId() {
|
||||
return actualMapId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Expected ID of the map.
|
||||
*/
|
||||
public String getExpectedMapId() {
|
||||
return expectedMapId;
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.insa.graphs.model.Graph;
|
||||
import org.insa.graphs.model.Path;
|
||||
|
||||
/**
|
||||
* Base interface that should be implemented by class used to read paths.
|
||||
*
|
||||
*/
|
||||
public interface PathReader extends AutoCloseable, Closeable {
|
||||
|
||||
/**
|
||||
* Read a path of the given graph and returns it.
|
||||
*
|
||||
* @param graph Graph of the path.
|
||||
*
|
||||
* @return Path read.
|
||||
*
|
||||
* @throws IOException When an error occurs while reading the path.
|
||||
*/
|
||||
public Path readPath(Graph graph) throws IOException;
|
||||
|
||||
/**
|
||||
* Close this graph reader.
|
||||
*
|
||||
* @throws IOException if an exception occurs while closing the reader.
|
||||
*
|
||||
*/
|
||||
public void close() throws IOException;
|
||||
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
package org.insa.graphs.model.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.insa.graphs.model.Path;
|
||||
|
||||
/**
|
||||
* Base interface that should be implemented by class used to write paths.
|
||||
*
|
||||
*/
|
||||
public interface PathWriter extends AutoCloseable, Closeable {
|
||||
|
||||
/**
|
||||
* Write the given path.
|
||||
*
|
||||
* @param path Path to write.
|
||||
*
|
||||
* @throws IOException When an error occurs while writing the path.
|
||||
*/
|
||||
public void writePath(Path path) throws IOException;
|
||||
|
||||
/**
|
||||
* Close this graph reader.
|
||||
*
|
||||
* @throws IOException if an exception occurs while closing the reader.
|
||||
*
|
||||
*/
|
||||
public void close() throws IOException;
|
||||
|
||||
}
|
@@ -0,0 +1,112 @@
|
||||
package org.insa.graphes.model;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.insa.graphs.model.Arc;
|
||||
import org.insa.graphs.model.Graph;
|
||||
import org.insa.graphs.model.Node;
|
||||
import org.insa.graphs.model.RoadInformation;
|
||||
import org.insa.graphs.model.RoadInformation.RoadType;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class GraphTest {
|
||||
|
||||
// Small graph use for tests
|
||||
private static Graph graph;
|
||||
|
||||
// List of nodes
|
||||
private static Node[] nodes;
|
||||
|
||||
@BeforeClass
|
||||
public static void initAll() throws IOException {
|
||||
|
||||
// Create nodes
|
||||
nodes = new Node[5];
|
||||
for (int i = 0; i < nodes.length; ++i) {
|
||||
nodes[i] = new Node(i, null);
|
||||
}
|
||||
|
||||
Node.linkNodes(nodes[0], nodes[1], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, false, 1, null),
|
||||
new ArrayList<>());
|
||||
Node.linkNodes(nodes[0], nodes[2], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, false, 1, null),
|
||||
new ArrayList<>());
|
||||
Node.linkNodes(nodes[0], nodes[4], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, true, 1, null), new ArrayList<>());
|
||||
Node.linkNodes(nodes[1], nodes[2], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, false, 1, null),
|
||||
new ArrayList<>());
|
||||
Node.linkNodes(nodes[2], nodes[3], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, true, 1, null), new ArrayList<>());
|
||||
Node.linkNodes(nodes[2], nodes[3], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, true, 1, null), new ArrayList<>());
|
||||
Node.linkNodes(nodes[2], nodes[3], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, true, 1, null), new ArrayList<>());
|
||||
Node.linkNodes(nodes[3], nodes[0], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, false, 1, null),
|
||||
new ArrayList<>());
|
||||
Node.linkNodes(nodes[3], nodes[4], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, true, 1, null), new ArrayList<>());
|
||||
Node.linkNodes(nodes[4], nodes[0], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, true, 1, null), new ArrayList<>());
|
||||
|
||||
graph = new Graph("ID", "", Arrays.asList(nodes), null);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of arcs between a and b.
|
||||
*/
|
||||
private List<Arc> getArcsBetween(Node a, Node b) {
|
||||
List<Arc> arcs = new ArrayList<>();
|
||||
for (Arc arc: a.getSuccessors()) {
|
||||
if (arc.getDestination().equals(b)) {
|
||||
arcs.add(arc);
|
||||
}
|
||||
}
|
||||
return arcs;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranspose() {
|
||||
Graph transpose = graph.transpose();
|
||||
|
||||
// Basic asserts...
|
||||
assertEquals("R/" + graph.getMapId(), transpose.getMapId());
|
||||
assertEquals(graph.size(), transpose.size());
|
||||
|
||||
final int expNbSucc[] = { 4, 2, 2, 4, 2 };
|
||||
for (int i = 0; i < expNbSucc.length; ++i) {
|
||||
assertEquals(expNbSucc[i], transpose.get(i).getNumberOfSuccessors());
|
||||
}
|
||||
|
||||
assertEquals(1, getArcsBetween(transpose.get(0), transpose.get(1)).size());
|
||||
assertEquals(1, getArcsBetween(transpose.get(0), transpose.get(2)).size());
|
||||
assertEquals(1, getArcsBetween(transpose.get(0), transpose.get(3)).size());
|
||||
assertEquals(1, getArcsBetween(transpose.get(0), transpose.get(4)).size());
|
||||
assertEquals(1, getArcsBetween(transpose.get(1), transpose.get(0)).size());
|
||||
assertEquals(1, getArcsBetween(transpose.get(1), transpose.get(2)).size());
|
||||
assertEquals(0, getArcsBetween(transpose.get(1), transpose.get(3)).size());
|
||||
assertEquals(0, getArcsBetween(transpose.get(1), transpose.get(4)).size());
|
||||
assertEquals(1, getArcsBetween(transpose.get(2), transpose.get(0)).size());
|
||||
assertEquals(1, getArcsBetween(transpose.get(2), transpose.get(1)).size());
|
||||
assertEquals(0, getArcsBetween(transpose.get(2), transpose.get(3)).size());
|
||||
assertEquals(0, getArcsBetween(transpose.get(2), transpose.get(4)).size());
|
||||
assertEquals(1, getArcsBetween(transpose.get(3), transpose.get(0)).size());
|
||||
assertEquals(0, getArcsBetween(transpose.get(3), transpose.get(1)).size());
|
||||
assertEquals(3, getArcsBetween(transpose.get(3), transpose.get(2)).size());
|
||||
assertEquals(0, getArcsBetween(transpose.get(3), transpose.get(4)).size());
|
||||
assertEquals(1, getArcsBetween(transpose.get(4), transpose.get(0)).size());
|
||||
assertEquals(0, getArcsBetween(transpose.get(4), transpose.get(1)).size());
|
||||
assertEquals(0, getArcsBetween(transpose.get(4), transpose.get(2)).size());
|
||||
assertEquals(1, getArcsBetween(transpose.get(4), transpose.get(3)).size());
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,92 @@
|
||||
package org.insa.graphes.model;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.insa.graphs.model.Arc;
|
||||
import org.insa.graphs.model.Node;
|
||||
import org.insa.graphs.model.RoadInformation;
|
||||
import org.insa.graphs.model.RoadInformation.RoadType;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class NodeTest {
|
||||
|
||||
// List of nodes
|
||||
private Node[] nodes;
|
||||
|
||||
@Before
|
||||
public void initAll() throws IOException {
|
||||
|
||||
// Create nodes
|
||||
nodes = new Node[6];
|
||||
for (int i = 0; i < nodes.length; ++i) {
|
||||
nodes[i] = new Node(i, null);
|
||||
}
|
||||
|
||||
Node.linkNodes(nodes[0], nodes[1], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, false, 1, null),
|
||||
new ArrayList<>());
|
||||
Node.linkNodes(nodes[0], nodes[2], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, false, 1, null),
|
||||
new ArrayList<>());
|
||||
Node.linkNodes(nodes[0], nodes[4], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, true, 1, null), new ArrayList<>());
|
||||
Node.linkNodes(nodes[1], nodes[2], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, false, 1, null),
|
||||
new ArrayList<>());
|
||||
Node.linkNodes(nodes[2], nodes[3], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, true, 1, null), new ArrayList<>());
|
||||
Node.linkNodes(nodes[2], nodes[3], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, true, 1, null), new ArrayList<>());
|
||||
Node.linkNodes(nodes[2], nodes[3], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, true, 1, null), new ArrayList<>());
|
||||
Node.linkNodes(nodes[3], nodes[0], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, false, 1, null),
|
||||
new ArrayList<>());
|
||||
Node.linkNodes(nodes[3], nodes[4], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, true, 1, null), new ArrayList<>());
|
||||
Node.linkNodes(nodes[4], nodes[0], 0,
|
||||
new RoadInformation(RoadType.UNCLASSIFIED, null, true, 1, null), new ArrayList<>());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The first arc between from a to b, or null.
|
||||
*/
|
||||
private Arc getFirstArcBetween(Node a, Node b) {
|
||||
for (Arc arc: a.getSuccessors()) {
|
||||
if (arc.getDestination().equals(b)) {
|
||||
return arc;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNumberOfSuccessors() {
|
||||
final int[] expNbSucc = { 4, 2, 5, 2, 1, 0 };
|
||||
assertEquals(expNbSucc.length, nodes.length);
|
||||
for (int i = 0; i < expNbSucc.length; ++i) {
|
||||
assertEquals(expNbSucc[i], nodes[i].getNumberOfSuccessors());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasSuccessors() {
|
||||
final int[] expNbSucc = { 4, 2, 5, 2, 1, 0 };
|
||||
assertEquals(expNbSucc.length, nodes.length);
|
||||
for (int i = 0; i < expNbSucc.length; ++i) {
|
||||
assertEquals(expNbSucc[i] != 0, nodes[i].hasSuccessors());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLinkNodes() {
|
||||
assertEquals(getFirstArcBetween(nodes[0], nodes[1]).getRoadInformation(),
|
||||
getFirstArcBetween(nodes[1], nodes[0]).getRoadInformation());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,243 @@
|
||||
package org.insa.graphes.model;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.insa.graphs.model.Arc;
|
||||
import org.insa.graphs.model.Graph;
|
||||
import org.insa.graphs.model.Node;
|
||||
import org.insa.graphs.model.Path;
|
||||
import org.insa.graphs.model.RoadInformation;
|
||||
import org.insa.graphs.model.RoadInformation.RoadType;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PathTest {
|
||||
|
||||
// Small graph use for tests
|
||||
private static Graph graph;
|
||||
|
||||
// List of nodes
|
||||
private static Node[] nodes;
|
||||
|
||||
// List of arcs in the graph, a2b is the arc from node A (0) to B (1).
|
||||
@SuppressWarnings("unused")
|
||||
private static Arc a2b, a2c, a2e, b2c, c2d_1, c2d_2, c2d_3, c2a, d2a, d2e, e2d;
|
||||
|
||||
// Some paths...
|
||||
private static Path emptyPath, singleNodePath, shortPath, longPath, loopPath, longLoopPath,
|
||||
invalidPath;
|
||||
|
||||
@BeforeClass
|
||||
public static void initAll() throws IOException {
|
||||
|
||||
// 10 and 20 meters per seconds
|
||||
RoadInformation speed10 = new RoadInformation(RoadType.MOTORWAY, null, true, 36, ""),
|
||||
speed20 = new RoadInformation(RoadType.MOTORWAY, null, true, 72, "");
|
||||
|
||||
// Create nodes
|
||||
nodes = new Node[5];
|
||||
for (int i = 0; i < nodes.length; ++i) {
|
||||
nodes[i] = new Node(i, null);
|
||||
}
|
||||
|
||||
// Add arcs...
|
||||
a2b = Node.linkNodes(nodes[0], nodes[1], 10, speed10, null);
|
||||
a2c = Node.linkNodes(nodes[0], nodes[2], 15, speed10, null);
|
||||
a2e = Node.linkNodes(nodes[0], nodes[4], 15, speed20, null);
|
||||
b2c = Node.linkNodes(nodes[1], nodes[2], 10, speed10, null);
|
||||
c2d_1 = Node.linkNodes(nodes[2], nodes[3], 20, speed10, null);
|
||||
c2d_2 = Node.linkNodes(nodes[2], nodes[3], 10, speed10, null);
|
||||
c2d_3 = Node.linkNodes(nodes[2], nodes[3], 15, speed20, null);
|
||||
d2a = Node.linkNodes(nodes[3], nodes[0], 15, speed10, null);
|
||||
d2e = Node.linkNodes(nodes[3], nodes[4], 22.8f, speed20, null);
|
||||
e2d = Node.linkNodes(nodes[4], nodes[0], 10, speed10, null);
|
||||
|
||||
graph = new Graph("ID", "", Arrays.asList(nodes), null);
|
||||
|
||||
emptyPath = new Path(graph, new ArrayList<Arc>());
|
||||
singleNodePath = new Path(graph, nodes[1]);
|
||||
shortPath = new Path(graph, Arrays.asList(new Arc[] { a2b, b2c, c2d_1 }));
|
||||
longPath = new Path(graph, Arrays.asList(new Arc[] { a2b, b2c, c2d_1, d2e }));
|
||||
loopPath = new Path(graph, Arrays.asList(new Arc[] { a2b, b2c, c2d_1, d2a }));
|
||||
longLoopPath = new Path(graph,
|
||||
Arrays.asList(new Arc[] { a2b, b2c, c2d_1, d2a, a2c, c2d_3, d2a, a2b, b2c }));
|
||||
invalidPath = new Path(graph, Arrays.asList(new Arc[] { a2b, c2d_1, d2e }));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConstructor() {
|
||||
assertEquals(graph, emptyPath.getGraph());
|
||||
assertEquals(graph, singleNodePath.getGraph());
|
||||
assertEquals(graph, shortPath.getGraph());
|
||||
assertEquals(graph, longPath.getGraph());
|
||||
assertEquals(graph, loopPath.getGraph());
|
||||
assertEquals(graph, longLoopPath.getGraph());
|
||||
assertEquals(graph, invalidPath.getGraph());
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testImmutability() {
|
||||
emptyPath.getArcs().add(a2b);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsEmpty() {
|
||||
assertTrue(emptyPath.isEmpty());
|
||||
|
||||
assertFalse(singleNodePath.isEmpty());
|
||||
assertFalse(shortPath.isEmpty());
|
||||
assertFalse(longPath.isEmpty());
|
||||
assertFalse(loopPath.isEmpty());
|
||||
assertFalse(longLoopPath.isEmpty());
|
||||
assertFalse(invalidPath.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSize() {
|
||||
assertEquals(0, emptyPath.size());
|
||||
assertEquals(1, singleNodePath.size());
|
||||
assertEquals(4, shortPath.size());
|
||||
assertEquals(5, longPath.size());
|
||||
assertEquals(5, loopPath.size());
|
||||
assertEquals(10, longLoopPath.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsValid() {
|
||||
assertTrue(emptyPath.isValid());
|
||||
assertTrue(singleNodePath.isValid());
|
||||
assertTrue(shortPath.isValid());
|
||||
assertTrue(longPath.isValid());
|
||||
assertTrue(loopPath.isValid());
|
||||
assertTrue(longLoopPath.isValid());
|
||||
|
||||
assertFalse(invalidPath.isValid());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLength() {
|
||||
assertEquals(0, emptyPath.getLength(), 1e-6);
|
||||
assertEquals(0, singleNodePath.getLength(), 1e-6);
|
||||
assertEquals(40, shortPath.getLength(), 1e-6);
|
||||
assertEquals(62.8, longPath.getLength(), 1e-6);
|
||||
assertEquals(55, loopPath.getLength(), 1e-6);
|
||||
assertEquals(120, longLoopPath.getLength(), 1e-6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTravelTime() {
|
||||
// Note: 18 km/h = 5m/s
|
||||
assertEquals(0, emptyPath.getTravelTime(18), 1e-6);
|
||||
assertEquals(0, singleNodePath.getTravelTime(18), 1e-6);
|
||||
assertEquals(8, shortPath.getTravelTime(18), 1e-6);
|
||||
assertEquals(12.56, longPath.getTravelTime(18), 1e-6);
|
||||
assertEquals(11, loopPath.getTravelTime(18), 1e-6);
|
||||
assertEquals(24, longLoopPath.getTravelTime(18), 1e-6);
|
||||
|
||||
// Note: 28.8 km/h = 8m/s
|
||||
assertEquals(0, emptyPath.getTravelTime(28.8), 1e-6);
|
||||
assertEquals(0, singleNodePath.getTravelTime(28.8), 1e-6);
|
||||
assertEquals(5, shortPath.getTravelTime(28.8), 1e-6);
|
||||
assertEquals(7.85, longPath.getTravelTime(28.8), 1e-6);
|
||||
assertEquals(6.875, loopPath.getTravelTime(28.8), 1e-6);
|
||||
assertEquals(15, longLoopPath.getTravelTime(28.8), 1e-6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMinimumTravelTime() {
|
||||
assertEquals(0, emptyPath.getMinimumTravelTime(), 1e-4);
|
||||
assertEquals(0, singleNodePath.getLength(), 1e-4);
|
||||
assertEquals(4, shortPath.getMinimumTravelTime(), 1e-4);
|
||||
assertEquals(5.14, longPath.getMinimumTravelTime(), 1e-4);
|
||||
assertEquals(5.5, loopPath.getMinimumTravelTime(), 1e-4);
|
||||
assertEquals(11.25, longLoopPath.getMinimumTravelTime(), 1e-4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFastestPathFromNodes() {
|
||||
Path path;
|
||||
Arc[] expected;
|
||||
|
||||
// Simple construction
|
||||
path = Path.createFastestPathFromNodes(graph,
|
||||
Arrays.asList(new Node[] { nodes[0], nodes[1], nodes[2] }));
|
||||
expected = new Arc[] { a2b, b2c };
|
||||
assertEquals(expected.length, path.getArcs().size());
|
||||
for (int i = 0; i < expected.length; ++i) {
|
||||
assertEquals(expected[i], path.getArcs().get(i));
|
||||
}
|
||||
|
||||
// Not so simple construction
|
||||
path = Path.createFastestPathFromNodes(graph,
|
||||
Arrays.asList(new Node[] { nodes[0], nodes[1], nodes[2], nodes[3] }));
|
||||
expected = new Arc[] { a2b, b2c, c2d_3 };
|
||||
assertEquals(expected.length, path.getArcs().size());
|
||||
for (int i = 0; i < expected.length; ++i) {
|
||||
assertEquals(expected[i], path.getArcs().get(i));
|
||||
}
|
||||
|
||||
// Trap construction!
|
||||
path = Path.createFastestPathFromNodes(graph, Arrays.asList(new Node[] { nodes[1] }));
|
||||
assertEquals(nodes[1], path.getOrigin());
|
||||
assertEquals(0, path.getArcs().size());
|
||||
|
||||
// Trap construction - The return!
|
||||
path = Path.createFastestPathFromNodes(graph, Arrays.asList(new Node[0]));
|
||||
assertEquals(null, path.getOrigin());
|
||||
assertEquals(0, path.getArcs().size());
|
||||
assertTrue(path.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateShortestPathFromNodes() {
|
||||
Path path;
|
||||
Arc[] expected;
|
||||
|
||||
// Simple construction
|
||||
path = Path.createShortestPathFromNodes(graph,
|
||||
Arrays.asList(new Node[] { nodes[0], nodes[1], nodes[2] }));
|
||||
expected = new Arc[] { a2b, b2c };
|
||||
assertEquals(expected.length, path.getArcs().size());
|
||||
for (int i = 0; i < expected.length; ++i) {
|
||||
assertEquals(expected[i], path.getArcs().get(i));
|
||||
}
|
||||
|
||||
// Not so simple construction
|
||||
path = Path.createShortestPathFromNodes(graph,
|
||||
Arrays.asList(new Node[] { nodes[0], nodes[1], nodes[2], nodes[3] }));
|
||||
expected = new Arc[] { a2b, b2c, c2d_2 };
|
||||
assertEquals(expected.length, path.getArcs().size());
|
||||
for (int i = 0; i < expected.length; ++i) {
|
||||
assertEquals(expected[i], path.getArcs().get(i));
|
||||
}
|
||||
|
||||
// Trap construction!
|
||||
path = Path.createShortestPathFromNodes(graph, Arrays.asList(new Node[] { nodes[1] }));
|
||||
assertEquals(nodes[1], path.getOrigin());
|
||||
assertEquals(0, path.getArcs().size());
|
||||
|
||||
// Trap construction - The return!
|
||||
path = Path.createShortestPathFromNodes(graph, Arrays.asList(new Node[0]));
|
||||
assertEquals(null, path.getOrigin());
|
||||
assertEquals(0, path.getArcs().size());
|
||||
assertTrue(path.isEmpty());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateFastestPathFromNodesException() {
|
||||
Path.createFastestPathFromNodes(graph, Arrays.asList(new Node[] { nodes[1], nodes[0] }));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateShortestPathFromNodesException() {
|
||||
Path.createShortestPathFromNodes(graph, Arrays.asList(new Node[] { nodes[1], nodes[0] }));
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user