123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- 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.
- *
- */
- public static Path createFastestPathFromNodes(Graph graph, List<Node> nodes)
- throws IllegalArgumentException {
- int nodeListSize = nodes.size();
-
- List<Arc> arcs = new ArrayList<Arc>(nodeListSize);
-
- if(nodeListSize > 1) {
- //nodes.size() - 1 because we look at i and i+1
- for(int i=0;i<nodes.size() - 1;i++) {
-
- //for each node we try to find fastestPath between i and i+1
- List<Arc> neighbourhood = nodes.get(i).getSuccessors();
-
- Arc fastestPath = null;
-
- for(Arc nextArc : neighbourhood) {
- if(nextArc.getDestination().compareTo(nodes.get(i+1)) == 0) {
- //here we find a path between i and i+1, now we need to see if it's the fastest one
- if(fastestPath == null) {
- fastestPath = nextArc;
- }
- else if(fastestPath.getMinimumTravelTime() > nextArc.getMinimumTravelTime()) {
- fastestPath = nextArc;
- }
- }
- }
-
- if(fastestPath == null) {
- throw new IllegalArgumentException();
- }
-
- arcs.add(fastestPath);
- }
- }
- else if (nodeListSize == 1) {
- return new Path(graph, nodes.get(0));
- }
- else {
- //nodeListSize == 0
- return new Path(graph);
- }
-
- 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.
- *
- *
- */
- public static Path createShortestPathFromNodes(Graph graph, List<Node> nodes)
- throws IllegalArgumentException {
-
- int nodeListSize = nodes.size();
-
- List<Arc> arcs = new ArrayList<Arc>(nodeListSize);
-
- if(nodeListSize > 1) {
- //nodes.size() - 1 because we look at i and i+1
- for(int i=0;i<nodes.size() - 1;i++) {
-
- //for each node we try to find shortestPath between i and i+1
- List<Arc> neighbourhood = nodes.get(i).getSuccessors();
-
- Arc shortestPath = null;
-
- for(Arc nextArc : neighbourhood) {
- if(nextArc.getDestination().compareTo(nodes.get(i+1)) == 0) {
- //here we find a path between i and i+1, now we need to see if it's the shortest one
- if(shortestPath == null) {
- shortestPath = nextArc;
- }
- else if(shortestPath.getLength() > nextArc.getLength()) {
- shortestPath = nextArc;
- }
- }
- }
-
- if(shortestPath == null) {
- throw new IllegalArgumentException();
- }
-
- arcs.add(shortestPath);
- }
- }
- else if (nodeListSize == 1) {
- return new Path(graph, nodes.get(0));
- }
- else {
- //nodeListSize == 0
- return new Path(graph);
- }
-
- 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.
- *
- */
- public boolean isValid() {
-
- if((this.isEmpty() && arcs.isEmpty()) || this.size() == 1) {
- return true;
- }
-
- //the first arc has for origin the origin of the path
- if(this.arcs.get(0).getOrigin() != this.origin) {
- return false;
- }
-
- //for two consecutive arcs, the destination of the first one is the origin of the second one
- for(int i = 0 ; i < arcs.size() - 1 ;i++) {
- if(arcs.get(i).getDestination().compareTo(arcs.get(i+1).getOrigin()) != 0) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Compute the length of this path (in meters).
- *
- * @return Total length of the path (in meters).
- *
- */
- public float getLength() {
-
- float totalLength = 0.0f;
-
- for(Arc arc : arcs) {
- totalLength += arc.getLength();
- }
-
-
- return totalLength;
- }
-
- /**
- * 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).
- *
- *
- */
- public double getTravelTime(double speed) {
- double totalTime = 0.0d;
-
- for(Arc arc : arcs) {
- totalTime += arc.getTravelTime(speed);
- }
-
-
- return totalTime;
- }
-
- /**
- * 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).
- *
- *
- */
- public double getMinimumTravelTime() {
- double totalTime = 0.0d;
-
- for(Arc arc : arcs) {
- totalTime += arc.getMinimumTravelTime();
- }
-
-
- return totalTime;
- }
-
- }
|