diff --git a/src/main/org/insa/graph/Arc.java b/src/main/org/insa/graph/Arc.java index 9d2eb16..5140884 100644 --- a/src/main/org/insa/graph/Arc.java +++ b/src/main/org/insa/graph/Arc.java @@ -7,6 +7,11 @@ import java.util.List; * class to allow us to represent two-ways roads in a memory efficient manner * (without having to duplicate attributes). * + * Arc should never be created manually but always using the + * {@link Node#linkNodes(Node, Node, int, RoadInformation, java.util.ArrayList)} + * method to ensure proper instantiation of the {@link ArcForward} and + * {@link ArcBackward} classes. + * * @see ArcForward * @see ArcBackward * diff --git a/src/main/org/insa/graph/ArcBackward.java b/src/main/org/insa/graph/ArcBackward.java index 36c841a..4a0aaaf 100644 --- a/src/main/org/insa/graph/ArcBackward.java +++ b/src/main/org/insa/graph/ArcBackward.java @@ -10,7 +10,7 @@ import java.util.List; * the original arc. * */ -public class ArcBackward implements Arc { +class ArcBackward implements Arc { // Original arc private final ArcForward originalArc; @@ -19,9 +19,9 @@ public class ArcBackward implements Arc { * Create a new backward arc which corresponds to the reverse arc of the given * arc. * - * @param originalArc + * @param originalArc Original forwarc arc corresponding to this backward arc. */ - public ArcBackward(ArcForward originalArc) { + protected ArcBackward(ArcForward originalArc) { this.originalArc = originalArc; this.originalArc.getDestination().addSuccessor(this); } diff --git a/src/main/org/insa/graph/ArcForward.java b/src/main/org/insa/graph/ArcForward.java index afd8173..ff20a77 100644 --- a/src/main/org/insa/graph/ArcForward.java +++ b/src/main/org/insa/graph/ArcForward.java @@ -24,7 +24,7 @@ public class ArcForward implements Arc { private final ArrayList points; /** - * Create a new arc and automatically link it with the given origin. + * Create a new ArcForward with the given attributes. * * @param origin Origin of this arc. * @param dest Destination of this arc. @@ -32,54 +32,44 @@ public class ArcForward implements Arc { * @param roadInformation Road information for this arc. * @param points Points representing this arc. */ - public ArcForward(Node origin, Node dest, int length, RoadInformation roadInformation, + protected ArcForward(Node origin, Node dest, int length, RoadInformation roadInformation, ArrayList points) { this.origin = origin; this.destination = dest; this.length = length; this.info = roadInformation; this.points = points; - origin.addSuccessor(this); } - /** - * {@inheritDoc} - */ + @Override public Node getOrigin() { return origin; } - /** - * {@inheritDoc} - */ + @Override public Node getDestination() { return destination; } - /** - * {@inheritDoc} - */ + @Override + public int getLength() { return length; } - /** - * {@inheritDoc} - */ + @Override + public double getMinimumTravelTime() { return getLength() * 3600.0 / (info.getMaximumSpeed() * 1000.0); } - /** - * {@inheritDoc} - */ + @Override + public RoadInformation getRoadInformation() { return info; } - /** - * {@inheritDoc} - */ + @Override public List getPoints() { return Collections.unmodifiableList(points); } diff --git a/src/main/org/insa/graph/Graph.java b/src/main/org/insa/graph/Graph.java index b96e5ea..09986b6 100644 --- a/src/main/org/insa/graph/Graph.java +++ b/src/main/org/insa/graph/Graph.java @@ -3,6 +3,13 @@ package org.insa.graph; import java.util.Collections; import java.util.List; +/** + * Main graph class. + * + * This class acts as a object-oriented adjacency list for a graph, i.e. it + * holds a list of nodes and each node holds a list of its successors. + * + */ public class Graph { // Map identifier. @@ -15,35 +22,39 @@ public class Graph { private final List nodes; // Graph information of this graph. - private final GraphInformation graphInfo; + private final GraphStatistics graphStatistics; /** - * @param mapId ID of this graph. - * @param list List of nodes for this graph. + * 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 list, GraphInformation graphInformation) { + public Graph(String mapId, String mapName, List nodes, GraphStatistics graphStatistics) { this.mapId = mapId; this.mapName = mapName; - this.nodes = list; - this.graphInfo = graphInformation; + this.nodes = nodes; + this.graphStatistics = graphStatistics; } /** - * @return GraphInformation of this graph. + * @return The GraphStatistics instance associated with this graph. */ - public GraphInformation getGraphInformation() { - return this.graphInfo; + public GraphStatistics getGraphInformation() { + return this.graphStatistics; } /** - * @return Immutable list of nodes of this graph. + * @return Immutable view of the list of nodes of this graph. */ public List getNodes() { return Collections.unmodifiableList(nodes); } /** - * @return Map ID of this graph. + * @return ID of the map associated with this graph. */ public String getMapId() { return mapId; @@ -57,7 +68,7 @@ public class Graph { } /** - * @return Return the transpose graph of this graph. + * @return Transpose graph of this graph. */ public Graph transpose() { // TODO: diff --git a/src/main/org/insa/graph/GraphInformation.java b/src/main/org/insa/graph/GraphInformation.java deleted file mode 100644 index 1d49b40..0000000 --- a/src/main/org/insa/graph/GraphInformation.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.insa.graph; - -/** - * Utility class that stores some information for a graph that are no easy to - * access quickly. - * - */ -public class GraphInformation { - - // Maximum speed on this graph (in kmph). - private final int maximumSpeed; - - // Maximum length of any arc on this graph. - private final int maximumLength; - - /** - * @param maximumSpeed - * @param maximumLength - */ - public GraphInformation(int maximumSpeed, int maximumLength) { - this.maximumLength = maximumLength; - this.maximumSpeed = maximumSpeed; - } - - /** - * @return Maximum speed of any arc in the graph. - */ - public int getMaximumSpeed() { - return this.maximumSpeed; - } - - /** - * @return Maximum length of any arc in the graph. - */ - public int getMaximumLength() { - return this.maximumLength; - } - -} diff --git a/src/main/org/insa/graph/GraphStatistics.java b/src/main/org/insa/graph/GraphStatistics.java new file mode 100644 index 0000000..fa6d115 --- /dev/null +++ b/src/main/org/insa/graph/GraphStatistics.java @@ -0,0 +1,46 @@ +package org.insa.graph; + +/** + * Utility class that stores some statistics of graphs that are not easy to + * access. + * + * This class is used to provide O(1) access to information in graph that do not + * change, and that usually require O(n) to compute. + * + */ +public class GraphStatistics { + + // Maximum speed on this graph (in kmph). + private final int maximumSpeed; + + // Maximum length of any arc on this graph. + private final int maximumLength; + + /** + * Create a new GraphStatistics instance with the given value. + * + * @param maximumSpeed Maximum speed of any road of the graph. A value of 0 may + * be used to indicate that this graph has no maximum limitation. + * @param maximumLength Maximum length of any arc of the graph. + */ + public GraphStatistics(int maximumSpeed, int maximumLength) { + this.maximumLength = maximumLength; + this.maximumSpeed = maximumSpeed; + } + + /** + * @return Maximum speed of any arc in the graph, or 0 if some road have no + * speed limitations. + */ + public int getMaximumSpeed() { + return this.maximumSpeed; + } + + /** + * @return Maximum length of any arc in the graph. + */ + public int getMaximumLength() { + return this.maximumLength; + } + +} diff --git a/src/main/org/insa/graph/Node.java b/src/main/org/insa/graph/Node.java index 6a93bdc..9620cfe 100644 --- a/src/main/org/insa/graph/Node.java +++ b/src/main/org/insa/graph/Node.java @@ -4,8 +4,43 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +/** + * Class representing a Node in a {@link Graph}. + * + * This class holds information regarding nodes in the graph together with the + * successors associated to the nodes. + * + * Nodes are comparable based on their ID. + * + */ public class Node implements Comparable { + /** + * Link the two given nodes with one or two arcs (depending on roadInformation), + * with the given attributes. + * + * If `roadInformation.isOneWay()` is 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. + * + * @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, int length, + RoadInformation roadInformation, ArrayList points) { + ArcForward arc = new ArcForward(origin, destination, length, roadInformation, points); + origin.addSuccessor(arc); + if (!roadInformation.isOneWay()) { + destination.addSuccessor(new ArcBackward(arc)); + } + return arc; + } + // ID of the node. private final int id; @@ -16,10 +51,11 @@ public class Node implements Comparable { private final ArrayList successors; /** - * Create a new Node corresponding to the given Point with an empty list of - * successors. + * Create a new Node with the given ID corresponding to the given Point with an + * empty list of successors. * - * @param point + * @param id ID of the node. + * @param point Position of the node. */ public Node(int id, Point point) { this.id = id; @@ -44,24 +80,19 @@ public class Node implements Comparable { } /** - * @return List of successors of this node. + * @return Immutable view of the list of successors of this node. */ public List getSuccessors() { return Collections.unmodifiableList(successors); } /** - * @return Point of this node. + * @return Location of this node. */ public Point getPoint() { return point; } - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ @Override public boolean equals(Object other) { if (other instanceof Node) { @@ -70,8 +101,10 @@ public class Node implements Comparable { return false; } - /* - * (non-Javadoc) + /** + * 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) */ diff --git a/src/main/org/insa/graph/Point.java b/src/main/org/insa/graph/Point.java index 6a0db35..509c4f9 100644 --- a/src/main/org/insa/graph/Point.java +++ b/src/main/org/insa/graph/Point.java @@ -1,20 +1,23 @@ package org.insa.graph; /** - * Class representing a point on Earth. + * Class representing a point (position) on Earth. * */ public final class Point { - // Earth radius, in meters; - private static final double EARTH_RADIUS = 6378137.0; + /** + * 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, p2 + * @param p1 First point. + * @param p2 second point. * - * @return Distance between the two given points, in meters. + * @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())) @@ -29,9 +32,10 @@ public final class 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. + * @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; @@ -55,7 +59,7 @@ public final class Point { /** * Compute the distance from this point to the given point * - * @param target Target point. + * @param target Target point to compute distance to. * * @return Distance between this point and the target point, in meters. */ @@ -63,11 +67,6 @@ public final class Point { return distance(this, target); } - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ @Override public String toString() { return String.format("Point(%f, %f)", getLongitude(), getLatitude()); diff --git a/src/main/org/insa/graph/RoadInformation.java b/src/main/org/insa/graph/RoadInformation.java index 1a2ad3a..fd6c3b4 100644 --- a/src/main/org/insa/graph/RoadInformation.java +++ b/src/main/org/insa/graph/RoadInformation.java @@ -3,6 +3,9 @@ package org.insa.graph; /** * Class containing information for road that may be shared by multiple arcs. * + * Sharing information between arcs reduces memory footprints of the program - A + * long road is often split into multiple arcs at each intersection. + * */ public class RoadInformation { @@ -45,6 +48,16 @@ public class RoadInformation { // 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; @@ -55,7 +68,7 @@ public class RoadInformation { } /** - * @return true if this is a private road. + * @return Access restrictions for this road. */ public AccessRestrictions getAccessRestrictions() { return this.access; @@ -69,14 +82,14 @@ public class RoadInformation { } /** - * @return true if this is a one-way road. + * @return true if the road is a one-way road. */ public boolean isOneWay() { return oneway; } /** - * @return Maximum speed for this road (in kmph). + * @return Maximum speed for this road (in kilometers-per-hour). */ public int getMaximumSpeed() { return maxSpeed; @@ -89,10 +102,6 @@ public class RoadInformation { return name; } - /* - * (non-Javadoc) - * @see java.lang.Object#toString() - */ @Override public String toString() { String typeAsString = "road"; diff --git a/src/main/org/insa/graph/io/BinaryGraphReaderInsa2018.java b/src/main/org/insa/graph/io/BinaryGraphReaderInsa2018.java index eb3eea5..999f224 100644 --- a/src/main/org/insa/graph/io/BinaryGraphReaderInsa2018.java +++ b/src/main/org/insa/graph/io/BinaryGraphReaderInsa2018.java @@ -8,10 +8,9 @@ import java.util.EnumMap; import org.insa.graph.AccessRestrictions; import org.insa.graph.AccessRestrictions.AccessMode; import org.insa.graph.AccessRestrictions.AccessRestriction; -import org.insa.graph.ArcBackward; -import org.insa.graph.ArcForward; +import org.insa.graph.Arc; import org.insa.graph.Graph; -import org.insa.graph.GraphInformation; +import org.insa.graph.GraphStatistics; import org.insa.graph.Node; import org.insa.graph.Point; import org.insa.graph.RoadInformation; @@ -41,7 +40,7 @@ public class BinaryGraphReaderInsa2018 extends BinaryReader implements GraphRead // 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[] { + final AccessRestriction[] allRestrictions = new AccessRestriction[]{ AccessRestriction.FORBIDDEN, AccessRestriction.ALLOWED, AccessRestriction.PRIVATE, AccessRestriction.DESTINATION, AccessRestriction.DELIVERY, AccessRestriction.CUSTOMERS, AccessRestriction.FORESTRY }; @@ -49,7 +48,7 @@ public class BinaryGraphReaderInsa2018 extends BinaryReader implements GraphRead // 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, + 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 }; @@ -240,16 +239,7 @@ public class BinaryGraphReaderInsa2018 extends BinaryReader implements GraphRead Node dest = nodes.get(destNode); // Add successor to initial arc. - ArcForward arc = new ArcForward(orig, dest, length, info, points); - - // And reverse arc if its a two-way road. - if (!info.isOneWay()) { - // Add without segments. - // ArrayList rPoints = new ArrayList(points); - // Collections.reverse(rPoints); - // new Arc(dest, orig, length, info, null); - new ArcBackward(arc); - } + Arc arc = Node.linkNodes(orig, dest, length, info, points); observers.forEach((observer) -> observer.notifyNewArcRead(arc)); } } @@ -261,7 +251,7 @@ public class BinaryGraphReaderInsa2018 extends BinaryReader implements GraphRead this.dis.close(); - return new Graph(mapId, mapName, nodes, new GraphInformation(maxSpeed, maxLength)); + return new Graph(mapId, mapName, nodes, new GraphStatistics(maxSpeed, maxLength)); } /** diff --git a/src/main/org/insa/graphics/drawing/components/BasicDrawing.java b/src/main/org/insa/graphics/drawing/components/BasicDrawing.java index ccffa77..b512699 100644 --- a/src/main/org/insa/graphics/drawing/components/BasicDrawing.java +++ b/src/main/org/insa/graphics/drawing/components/BasicDrawing.java @@ -22,7 +22,6 @@ import java.util.List; import javax.swing.JPanel; import org.insa.graph.Arc; -import org.insa.graph.ArcForward; import org.insa.graph.Graph; import org.insa.graph.Node; import org.insa.graph.Path; @@ -395,7 +394,6 @@ public class BasicDrawing extends JPanel implements Drawing { /* * (non-Javadoc) - * * @see org.insa.graphics.drawing.Drawing#clear() */ @Override @@ -411,7 +409,6 @@ public class BasicDrawing extends JPanel implements Drawing { /* * (non-Javadoc) - * * @see org.insa.graphics.drawing.Drawing#clearOverlays() */ @Override @@ -472,7 +469,6 @@ public class BasicDrawing extends JPanel implements Drawing { /* * (non-Javadoc) - * * @see * org.insa.graphics.drawing.Drawing#addDrawingClickListener(org.insa.graphics. * drawing.DrawingClickListener) @@ -484,7 +480,6 @@ public class BasicDrawing extends JPanel implements Drawing { /* * (non-Javadoc) - * * @see org.insa.graphics.drawing.Drawing#removeDrawingClickListener(org.insa. * graphics.drawing.DrawingClickListener) */ @@ -528,9 +523,9 @@ public class BasicDrawing extends JPanel implements Drawing { * * @param arc Arc to draw. * @param palette Palette to use to retrieve color and width for arc, or null to - * use current settings. + * use current settings. */ - protected void drawArc(ArcForward arc, GraphPalette palette, boolean repaint) { + protected void drawArc(Arc arc, GraphPalette palette, boolean repaint) { List pts = arc.getPoints(); if (!pts.isEmpty()) { if (palette != null) { @@ -645,8 +640,11 @@ public class BasicDrawing extends JPanel implements Drawing { for (Node node: graph.getNodes()) { for (Arc arc: node.getSuccessors()) { - if (arc instanceof ArcForward) { // draw only "true" arcs - drawArc((ArcForward) arc, palette, false); + // Draw arcs only if there are one-way arcs or if origin is lower than + // destination, avoid drawing two-ways arc twice. + if (arc.getRoadInformation().isOneWay() + || arc.getOrigin().compareTo(arc.getDestination()) < 0) { + drawArc(arc, palette, false); } } if (node.getId() % repaintModulo == 0) {