Update javadoc, clean Arc implementation.

This commit is contained in:
Mikael Capelle 2018-03-07 16:51:03 +01:00
parent 1454e651dc
commit 04bddb0d34
11 changed files with 174 additions and 132 deletions

View File

@ -7,6 +7,11 @@ import java.util.List;
* class to allow us to represent two-ways roads in a memory efficient manner * class to allow us to represent two-ways roads in a memory efficient manner
* (without having to duplicate attributes). * (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 ArcForward
* @see ArcBackward * @see ArcBackward
* *

View File

@ -10,7 +10,7 @@ import java.util.List;
* the original arc. * the original arc.
* *
*/ */
public class ArcBackward implements Arc { class ArcBackward implements Arc {
// Original arc // Original arc
private final ArcForward originalArc; 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 * Create a new backward arc which corresponds to the reverse arc of the given
* arc. * 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 = originalArc;
this.originalArc.getDestination().addSuccessor(this); this.originalArc.getDestination().addSuccessor(this);
} }

View File

@ -24,7 +24,7 @@ public class ArcForward implements Arc {
private final ArrayList<Point> points; private final ArrayList<Point> 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 origin Origin of this arc.
* @param dest Destination 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 roadInformation Road information for this arc.
* @param points Points representing 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<Point> points) { ArrayList<Point> points) {
this.origin = origin; this.origin = origin;
this.destination = dest; this.destination = dest;
this.length = length; this.length = length;
this.info = roadInformation; this.info = roadInformation;
this.points = points; this.points = points;
origin.addSuccessor(this);
} }
/** @Override
* {@inheritDoc}
*/
public Node getOrigin() { public Node getOrigin() {
return origin; return origin;
} }
/** @Override
* {@inheritDoc}
*/
public Node getDestination() { public Node getDestination() {
return destination; return destination;
} }
/** @Override
* {@inheritDoc}
*/
public int getLength() { public int getLength() {
return length; return length;
} }
/** @Override
* {@inheritDoc}
*/
public double getMinimumTravelTime() { public double getMinimumTravelTime() {
return getLength() * 3600.0 / (info.getMaximumSpeed() * 1000.0); return getLength() * 3600.0 / (info.getMaximumSpeed() * 1000.0);
} }
/** @Override
* {@inheritDoc}
*/
public RoadInformation getRoadInformation() { public RoadInformation getRoadInformation() {
return info; return info;
} }
/** @Override
* {@inheritDoc}
*/
public List<Point> getPoints() { public List<Point> getPoints() {
return Collections.unmodifiableList(points); return Collections.unmodifiableList(points);
} }

View File

@ -3,6 +3,13 @@ package org.insa.graph;
import java.util.Collections; import java.util.Collections;
import java.util.List; 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 { public class Graph {
// Map identifier. // Map identifier.
@ -15,35 +22,39 @@ public class Graph {
private final List<Node> nodes; private final List<Node> nodes;
// Graph information of this graph. // Graph information of this graph.
private final GraphInformation graphInfo; private final GraphStatistics graphStatistics;
/** /**
* @param mapId ID of this graph. * Create a new graph with the given ID, name, nodes and information.
* @param list List of nodes for this graph. *
* @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> list, GraphInformation graphInformation) { public Graph(String mapId, String mapName, List<Node> nodes, GraphStatistics graphStatistics) {
this.mapId = mapId; this.mapId = mapId;
this.mapName = mapName; this.mapName = mapName;
this.nodes = list; this.nodes = nodes;
this.graphInfo = graphInformation; this.graphStatistics = graphStatistics;
} }
/** /**
* @return GraphInformation of this graph. * @return The GraphStatistics instance associated with this graph.
*/ */
public GraphInformation getGraphInformation() { public GraphStatistics getGraphInformation() {
return this.graphInfo; return this.graphStatistics;
} }
/** /**
* @return Immutable list of nodes of this graph. * @return Immutable view of the list of nodes of this graph.
*/ */
public List<Node> getNodes() { public List<Node> getNodes() {
return Collections.unmodifiableList(nodes); return Collections.unmodifiableList(nodes);
} }
/** /**
* @return Map ID of this graph. * @return ID of the map associated with this graph.
*/ */
public String getMapId() { public String getMapId() {
return mapId; 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() { public Graph transpose() {
// TODO: // TODO:

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -4,8 +4,43 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; 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<Node> { public class Node implements Comparable<Node> {
/**
* 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<Point> 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. // ID of the node.
private final int id; private final int id;
@ -16,10 +51,11 @@ public class Node implements Comparable<Node> {
private final ArrayList<Arc> successors; private final ArrayList<Arc> successors;
/** /**
* Create a new Node corresponding to the given Point with an empty list of * Create a new Node with the given ID corresponding to the given Point with an
* successors. * empty list of successors.
* *
* @param point * @param id ID of the node.
* @param point Position of the node.
*/ */
public Node(int id, Point point) { public Node(int id, Point point) {
this.id = id; this.id = id;
@ -44,24 +80,19 @@ public class Node implements Comparable<Node> {
} }
/** /**
* @return List of successors of this node. * @return Immutable view of the list of successors of this node.
*/ */
public List<Arc> getSuccessors() { public List<Arc> getSuccessors() {
return Collections.unmodifiableList(successors); return Collections.unmodifiableList(successors);
} }
/** /**
* @return Point of this node. * @return Location of this node.
*/ */
public Point getPoint() { public Point getPoint() {
return point; return point;
} }
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
if (other instanceof Node) { if (other instanceof Node) {
@ -70,8 +101,10 @@ public class Node implements Comparable<Node> {
return false; 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) * @see java.lang.Comparable#compareTo(java.lang.Object)
*/ */

View File

@ -1,20 +1,23 @@
package org.insa.graph; package org.insa.graph;
/** /**
* Class representing a point on Earth. * Class representing a point (position) on Earth.
* *
*/ */
public final class Point { 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. * 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) { public static double distance(Point p1, Point p2) {
double sinLat = Math.sin(Math.toRadians(p1.getLatitude())) double sinLat = Math.sin(Math.toRadians(p1.getLatitude()))
@ -29,9 +32,10 @@ public final class Point {
private final float longitude, latitude; 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 longitude Longitude of the point (in degrees).
* @param latitude Latitude of the point, in degrees. * @param latitude Latitude of the point (in degrees).
*/ */
public Point(float longitude, float latitude) { public Point(float longitude, float latitude) {
this.longitude = longitude; this.longitude = longitude;
@ -55,7 +59,7 @@ public final class Point {
/** /**
* Compute the distance from this point to the given 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. * @return Distance between this point and the target point, in meters.
*/ */
@ -63,11 +67,6 @@ public final class Point {
return distance(this, target); return distance(this, target);
} }
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override @Override
public String toString() { public String toString() {
return String.format("Point(%f, %f)", getLongitude(), getLatitude()); return String.format("Point(%f, %f)", getLongitude(), getLatitude());

View File

@ -3,6 +3,9 @@ package org.insa.graph;
/** /**
* Class containing information for road that may be shared by multiple arcs. * 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 { public class RoadInformation {
@ -45,6 +48,16 @@ public class RoadInformation {
// Name of the road. // Name of the road.
private final String name; 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, public RoadInformation(RoadType roadType, AccessRestrictions access, boolean isOneWay,
int maxSpeed, String name) { int maxSpeed, String name) {
this.type = roadType; 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() { public AccessRestrictions getAccessRestrictions() {
return this.access; 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() { public boolean isOneWay() {
return oneway; return oneway;
} }
/** /**
* @return Maximum speed for this road (in kmph). * @return Maximum speed for this road (in kilometers-per-hour).
*/ */
public int getMaximumSpeed() { public int getMaximumSpeed() {
return maxSpeed; return maxSpeed;
@ -89,10 +102,6 @@ public class RoadInformation {
return name; return name;
} }
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override @Override
public String toString() { public String toString() {
String typeAsString = "road"; String typeAsString = "road";

View File

@ -8,10 +8,9 @@ import java.util.EnumMap;
import org.insa.graph.AccessRestrictions; import org.insa.graph.AccessRestrictions;
import org.insa.graph.AccessRestrictions.AccessMode; import org.insa.graph.AccessRestrictions.AccessMode;
import org.insa.graph.AccessRestrictions.AccessRestriction; import org.insa.graph.AccessRestrictions.AccessRestriction;
import org.insa.graph.ArcBackward; import org.insa.graph.Arc;
import org.insa.graph.ArcForward;
import org.insa.graph.Graph; import org.insa.graph.Graph;
import org.insa.graph.GraphInformation; import org.insa.graph.GraphStatistics;
import org.insa.graph.Node; import org.insa.graph.Node;
import org.insa.graph.Point; import org.insa.graph.Point;
import org.insa.graph.RoadInformation; 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 // 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 // 2) - UKNOWN is not included because value above 6 (FORESTRY) are all
// considered unknown. // considered unknown.
final AccessRestriction[] allRestrictions = new AccessRestriction[] { final AccessRestriction[] allRestrictions = new AccessRestriction[]{
AccessRestriction.FORBIDDEN, AccessRestriction.ALLOWED, AccessRestriction.PRIVATE, AccessRestriction.FORBIDDEN, AccessRestriction.ALLOWED, AccessRestriction.PRIVATE,
AccessRestriction.DESTINATION, AccessRestriction.DELIVERY, AccessRestriction.DESTINATION, AccessRestriction.DELIVERY,
AccessRestriction.CUSTOMERS, AccessRestriction.FORESTRY }; 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 // 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, // 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. // 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.SMALL_MOTORCYCLE, AccessMode.AGRICULTURAL, AccessMode.MOTORCYCLE,
AccessMode.MOTORCAR, AccessMode.HEAVY_GOODS, null, AccessMode.PUBLIC_TRANSPORT }; 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); Node dest = nodes.get(destNode);
// Add successor to initial arc. // Add successor to initial arc.
ArcForward arc = new ArcForward(orig, dest, length, info, points); Arc arc = Node.linkNodes(orig, dest, length, info, points);
// And reverse arc if its a two-way road.
if (!info.isOneWay()) {
// Add without segments.
// ArrayList<Point> rPoints = new ArrayList<Point>(points);
// Collections.reverse(rPoints);
// new Arc(dest, orig, length, info, null);
new ArcBackward(arc);
}
observers.forEach((observer) -> observer.notifyNewArcRead(arc)); observers.forEach((observer) -> observer.notifyNewArcRead(arc));
} }
} }
@ -261,7 +251,7 @@ public class BinaryGraphReaderInsa2018 extends BinaryReader implements GraphRead
this.dis.close(); this.dis.close();
return new Graph(mapId, mapName, nodes, new GraphInformation(maxSpeed, maxLength)); return new Graph(mapId, mapName, nodes, new GraphStatistics(maxSpeed, maxLength));
} }
/** /**

View File

@ -22,7 +22,6 @@ import java.util.List;
import javax.swing.JPanel; import javax.swing.JPanel;
import org.insa.graph.Arc; import org.insa.graph.Arc;
import org.insa.graph.ArcForward;
import org.insa.graph.Graph; import org.insa.graph.Graph;
import org.insa.graph.Node; import org.insa.graph.Node;
import org.insa.graph.Path; import org.insa.graph.Path;
@ -395,7 +394,6 @@ public class BasicDrawing extends JPanel implements Drawing {
/* /*
* (non-Javadoc) * (non-Javadoc)
*
* @see org.insa.graphics.drawing.Drawing#clear() * @see org.insa.graphics.drawing.Drawing#clear()
*/ */
@Override @Override
@ -411,7 +409,6 @@ public class BasicDrawing extends JPanel implements Drawing {
/* /*
* (non-Javadoc) * (non-Javadoc)
*
* @see org.insa.graphics.drawing.Drawing#clearOverlays() * @see org.insa.graphics.drawing.Drawing#clearOverlays()
*/ */
@Override @Override
@ -472,7 +469,6 @@ public class BasicDrawing extends JPanel implements Drawing {
/* /*
* (non-Javadoc) * (non-Javadoc)
*
* @see * @see
* org.insa.graphics.drawing.Drawing#addDrawingClickListener(org.insa.graphics. * org.insa.graphics.drawing.Drawing#addDrawingClickListener(org.insa.graphics.
* drawing.DrawingClickListener) * drawing.DrawingClickListener)
@ -484,7 +480,6 @@ public class BasicDrawing extends JPanel implements Drawing {
/* /*
* (non-Javadoc) * (non-Javadoc)
*
* @see org.insa.graphics.drawing.Drawing#removeDrawingClickListener(org.insa. * @see org.insa.graphics.drawing.Drawing#removeDrawingClickListener(org.insa.
* graphics.drawing.DrawingClickListener) * graphics.drawing.DrawingClickListener)
*/ */
@ -530,7 +525,7 @@ public class BasicDrawing extends JPanel implements Drawing {
* @param palette Palette to use to retrieve color and width for arc, or null to * @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<Point> pts = arc.getPoints(); List<Point> pts = arc.getPoints();
if (!pts.isEmpty()) { if (!pts.isEmpty()) {
if (palette != null) { if (palette != null) {
@ -645,8 +640,11 @@ public class BasicDrawing extends JPanel implements Drawing {
for (Node node: graph.getNodes()) { for (Node node: graph.getNodes()) {
for (Arc arc: node.getSuccessors()) { for (Arc arc: node.getSuccessors()) {
if (arc instanceof ArcForward) { // draw only "true" arcs // Draw arcs only if there are one-way arcs or if origin is lower than
drawArc((ArcForward) arc, palette, false); // 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) { if (node.getId() % repaintModulo == 0) {