Browse Source

New updates.

Holt59 6 years ago
parent
commit
aab8743d3c
24 changed files with 907 additions and 402 deletions
  1. 36
    56
      src/main/org/insa/algo/AbstractInputData.java
  2. 0
    71
      src/main/org/insa/algo/ArcFilterFactory.java
  3. 43
    0
      src/main/org/insa/algo/ArcInspector.java
  4. 149
    0
      src/main/org/insa/algo/ArcInspectorFactory.java
  5. 3
    2
      src/main/org/insa/algo/carpooling/CarPoolingData.java
  6. 3
    2
      src/main/org/insa/algo/packageswitch/PackageSwitchData.java
  7. 83
    86
      src/main/org/insa/algo/shortestpath/BellmanFordAlgorithm.java
  8. 6
    22
      src/main/org/insa/algo/shortestpath/ShortestPathData.java
  9. 9
    5
      src/main/org/insa/algo/shortestpath/ShortestPathSolution.java
  10. 13
    39
      src/main/org/insa/algo/utils/BinaryHeap.java
  11. 64
    0
      src/main/org/insa/algo/utils/BinarySearchTree.java
  12. 32
    0
      src/main/org/insa/algo/utils/ElementNotFoundException.java
  13. 16
    0
      src/main/org/insa/algo/utils/EmptyPriorityQueueException.java
  14. 54
    0
      src/main/org/insa/algo/utils/PriorityQueue.java
  15. 1
    1
      src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsData.java
  16. 2
    0
      src/main/org/insa/base/Launch.java
  17. 2
    0
      src/main/org/insa/graph/GraphStatistics.java
  18. 13
    54
      src/main/org/insa/graphics/AlgorithmPanel.java
  19. 5
    6
      src/main/org/insa/graphics/MainWindow.java
  20. 88
    36
      src/main/org/insa/graphics/drawing/components/BasicDrawing.java
  21. 2
    1
      src/main/org/insa/graphics/drawing/overlays/MarkerAutoScaling.java
  22. 0
    2
      src/main/org/insa/graphics/drawing/overlays/MarkerUtils.java
  23. 88
    19
      src/test/org/insa/algo/utils/BinaryHeapTest.java
  24. 195
    0
      src/test/org/insa/algo/utils/BinarySearchTreeTest.java

+ 36
- 56
src/main/org/insa/algo/AbstractInputData.java View File

@@ -2,6 +2,7 @@ package org.insa.algo;
2 2
 
3 3
 import org.insa.graph.Arc;
4 4
 import org.insa.graph.Graph;
5
+import org.insa.graph.GraphStatistics;
5 6
 
6 7
 /**
7 8
  * Base class for algorithm input data classes. This class contains the basic
@@ -12,93 +13,72 @@ import org.insa.graph.Graph;
12 13
 public abstract class AbstractInputData {
13 14
 
14 15
     /**
15
-     * Mode for computing costs on the arc (time or length).
16
-     *
16
+     * Enum specifying the top mode of the algorithms.
17
+     * 
18
+     * @see ArcInspector
17 19
      */
18 20
     public enum Mode {
19 21
         TIME, LENGTH
20 22
     }
21 23
 
22
-    /**
23
-     * Filtering interface for arcs - This class can be used to indicate to an
24
-     * algorithm which arc can be used.
25
-     *
26
-     */
27
-    public interface ArcFilter {
28
-
29
-        /**
30
-         * Check if the given arc can be used (is allowed).
31
-         * 
32
-         * @param arc Arc to check.
33
-         * 
34
-         * @return true if the given arc is allowed.
35
-         */
36
-        public boolean isAllowed(Arc arc);
37
-
38
-    }
39
-
40 24
     // Graph
41 25
     private final Graph graph;
42 26
 
43
-    // Mode for the computation of the costs.
44
-    private final Mode mode;
45
-
46 27
     // Arc filter.
47
-    private final ArcFilter arcFilter;
28
+    protected final ArcInspector arcInspector;
48 29
 
49 30
     /**
50 31
      * Create a new AbstractInputData instance for the given graph, mode and filter.
51 32
      * 
52
-     * @param graph
53
-     * @parma mode
54
-     * @param arcFilter
33
+     * @param graph Graph for this input data.
34
+     * @param arcInspector Arc inspector for this input data.
55 35
      */
56
-    protected AbstractInputData(Graph graph, Mode mode, ArcFilter arcFilter) {
36
+    protected AbstractInputData(Graph graph, ArcInspector arcInspector) {
57 37
         this.graph = graph;
58
-        this.mode = mode;
59
-        this.arcFilter = arcFilter;
38
+        this.arcInspector = arcInspector;
60 39
     }
61 40
 
62 41
     /**
63
-     * Create a new AbstractInputData instance for the given graph and mode, with no
64
-     * filtering on the arc.
65
-     * 
66
-     * @param graph
67
-     * @param mode
42
+     * @return Graph associated with this input.
68 43
      */
69
-    protected AbstractInputData(Graph graph, Mode mode) {
70
-        this(graph, mode, new AbstractInputData.ArcFilter() {
71
-            @Override
72
-            public boolean isAllowed(Arc arc) {
73
-                return true;
74
-            }
75
-        });
44
+    public Graph getGraph() {
45
+        return graph;
76 46
     }
77 47
 
78 48
     /**
79
-     * Create a new AbstractInputData instance for the given graph, with default
80
-     * mode (LENGHT), with no filtering on the arc.
49
+     * Retrieve the cost associated with the given arc according to the underlying
50
+     * arc inspector.
51
+     * 
52
+     * @param arc Arc for which cost should be retrieved.
53
+     * 
54
+     * @return Cost for the given arc.
81 55
      * 
82
-     * @param graph
56
+     * @see ArcInspector
83 57
      */
84
-    protected AbstractInputData(Graph graph) {
85
-        this(graph, Mode.LENGTH);
58
+    public double getCost(Arc arc) {
59
+        return this.arcInspector.getCost(arc);
86 60
     }
87 61
 
88 62
     /**
89
-     * @return Graph associated with this input.
63
+     * @return Mode associated with this input data.
64
+     * 
65
+     * @see Mode
90 66
      */
91
-    public Graph getGraph() {
92
-        return graph;
67
+    public Mode getMode() {
68
+        return this.arcInspector.getMode();
93 69
     }
94 70
 
95 71
     /**
96
-     * @return Mode of the algorithm (time or length).
72
+     * Retrieve the maximum speed associated with this input data, or
73
+     * {@link GraphStatistics#NO_MAXIMUM_SPEED} if none is associated. The maximum
74
+     * speed associated with input data is different from the maximum speed
75
+     * associated with graph (accessible via {@link Graph#getGraphInformation()}).
97 76
      * 
98
-     * @see Mode
77
+     * @return The maximum speed for this inspector, or
78
+     *         {@link GraphStatistics#NO_MAXIMUM_SPEED} if none is set.
99 79
      */
100
-    public Mode getMode() {
101
-        return mode;
80
+    public int getMaximumSpeed() {
81
+        return this.arcInspector.getMaximumSpeed();
102 82
     }
103 83
 
104 84
     /**
@@ -108,10 +88,10 @@ public abstract class AbstractInputData {
108 88
      * 
109 89
      * @return true if the given arc is allowed.
110 90
      * 
111
-     * @see ArcFilter
91
+     * @see ArcInspector
112 92
      */
113 93
     public boolean isAllowed(Arc arc) {
114
-        return this.arcFilter.isAllowed(arc);
94
+        return this.arcInspector.isAllowed(arc);
115 95
     }
116 96
 
117 97
 }

+ 0
- 71
src/main/org/insa/algo/ArcFilterFactory.java View File

@@ -1,71 +0,0 @@
1
-package org.insa.algo;
2
-
3
-import java.util.ArrayList;
4
-import java.util.EnumSet;
5
-import java.util.List;
6
-
7
-import org.insa.algo.AbstractInputData.ArcFilter;
8
-import org.insa.graph.AccessRestrictions.AccessMode;
9
-import org.insa.graph.AccessRestrictions.AccessRestriction;
10
-import org.insa.graph.Arc;
11
-
12
-public class ArcFilterFactory {
13
-
14
-    /**
15
-     * @return List of all arc filters in this factory.
16
-     */
17
-    public static List<ArcFilter> getAllFilters() {
18
-        List<ArcFilter> filters = new ArrayList<>();
19
-
20
-        // Common filters:
21
-
22
-        // 1. No filter (all arcs allowed):
23
-        filters.add(new ArcFilter() {
24
-            @Override
25
-            public boolean isAllowed(Arc arc) {
26
-                return true;
27
-            }
28
-
29
-            @Override
30
-            public String toString() {
31
-                return "All roads are allowed.";
32
-            }
33
-        });
34
-
35
-        // 2. Only road allowed for cars:
36
-        filters.add(new ArcFilter() {
37
-            @Override
38
-            public boolean isAllowed(Arc arc) {
39
-                return arc.getRoadInformation().getAccessRestrictions()
40
-                        .isAllowedForAny(AccessMode.MOTORCAR, EnumSet.complementOf(EnumSet
41
-                                .of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
42
-            }
43
-
44
-            @Override
45
-            public String toString() {
46
-                return "Only roads open for cars.";
47
-            }
48
-        });
49
-
50
-        // 3. Non-private roads for pedestrian and bicycle:
51
-        filters.add(new ArcFilter() {
52
-            @Override
53
-            public boolean isAllowed(Arc arc) {
54
-                return arc.getRoadInformation().getAccessRestrictions()
55
-                        .isAllowedForAny(AccessMode.FOOT, EnumSet.complementOf(EnumSet
56
-                                .of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
57
-            }
58
-
59
-            @Override
60
-            public String toString() {
61
-                return "Non-private roads for pedestrian.";
62
-            }
63
-        });
64
-
65
-        // 3. Add your own filters here (do not forget to implement toString() to get an
66
-        // understandable output!):
67
-
68
-        return filters;
69
-    }
70
-
71
-}

+ 43
- 0
src/main/org/insa/algo/ArcInspector.java View File

@@ -0,0 +1,43 @@
1
+package org.insa.algo;
2
+
3
+import org.insa.algo.AbstractInputData.Mode;
4
+import org.insa.graph.Arc;
5
+import org.insa.graph.GraphStatistics;
6
+
7
+/**
8
+ * This class can be used to indicate to an algorithm which arcs can be used and
9
+ * the costs of the usable arcs..
10
+ *
11
+ */
12
+public interface ArcInspector {
13
+
14
+    /**
15
+     * Check if the given arc can be used (is allowed).
16
+     * 
17
+     * @param arc Arc to check.
18
+     * 
19
+     * @return true if the given arc is allowed.
20
+     */
21
+    public boolean isAllowed(Arc arc);
22
+
23
+    /**
24
+     * Find the cost of the given arc.
25
+     * 
26
+     * @param arc Arc for which the cost should be returned.
27
+     * 
28
+     * @return Cost of the arc.
29
+     */
30
+    public double getCost(Arc arc);
31
+
32
+    /**
33
+     * @return The maximum speed for this inspector, or
34
+     *         {@link GraphStatistics#NO_MAXIMUM_SPEED} if none is set.
35
+     */
36
+    public int getMaximumSpeed();
37
+
38
+    /**
39
+     * @return Mode for this arc inspector.
40
+     */
41
+    public Mode getMode();
42
+
43
+}

+ 149
- 0
src/main/org/insa/algo/ArcInspectorFactory.java View File

@@ -0,0 +1,149 @@
1
+package org.insa.algo;
2
+
3
+import java.util.ArrayList;
4
+import java.util.EnumSet;
5
+import java.util.List;
6
+
7
+import org.insa.algo.AbstractInputData.Mode;
8
+import org.insa.graph.AccessRestrictions.AccessMode;
9
+import org.insa.graph.AccessRestrictions.AccessRestriction;
10
+import org.insa.graph.Arc;
11
+import org.insa.graph.GraphStatistics;
12
+
13
+public class ArcInspectorFactory {
14
+
15
+    /**
16
+     * @return List of all arc filters in this factory.
17
+     */
18
+    public static List<ArcInspector> getAllFilters() {
19
+        List<ArcInspector> filters = new ArrayList<>();
20
+
21
+        // Common filters:
22
+
23
+        // No filter (all arcs allowed):
24
+        filters.add(new ArcInspector() {
25
+            @Override
26
+            public boolean isAllowed(Arc arc) {
27
+                return true;
28
+            }
29
+
30
+            @Override
31
+            public double getCost(Arc arc) {
32
+                return arc.getLength();
33
+            }
34
+
35
+            @Override
36
+            public int getMaximumSpeed() {
37
+                return GraphStatistics.NO_MAXIMUM_SPEED;
38
+            }
39
+
40
+            @Override
41
+            public Mode getMode() {
42
+                return Mode.LENGTH;
43
+            }
44
+
45
+            @Override
46
+            public String toString() {
47
+                return "Shortest path, all roads allowed";
48
+            }
49
+        });
50
+
51
+        // Only road allowed for cars and length:
52
+        filters.add(new ArcInspector() {
53
+            @Override
54
+            public boolean isAllowed(Arc arc) {
55
+                return arc.getRoadInformation().getAccessRestrictions()
56
+                        .isAllowedForAny(AccessMode.MOTORCAR, EnumSet.complementOf(EnumSet
57
+                                .of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
58
+            }
59
+
60
+            @Override
61
+            public double getCost(Arc arc) {
62
+                return arc.getLength();
63
+            }
64
+
65
+            @Override
66
+            public int getMaximumSpeed() {
67
+                return GraphStatistics.NO_MAXIMUM_SPEED;
68
+            }
69
+
70
+            @Override
71
+            public Mode getMode() {
72
+                return Mode.LENGTH;
73
+            }
74
+
75
+            @Override
76
+            public String toString() {
77
+                return "Shortest path, only roads open for cars";
78
+            }
79
+        });
80
+
81
+        // Only road allowed for cars and time:
82
+        filters.add(new ArcInspector() {
83
+            @Override
84
+            public boolean isAllowed(Arc arc) {
85
+                return arc.getRoadInformation().getAccessRestrictions()
86
+                        .isAllowedForAny(AccessMode.MOTORCAR, EnumSet.complementOf(EnumSet
87
+                                .of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
88
+            }
89
+
90
+            @Override
91
+            public double getCost(Arc arc) {
92
+                return arc.getMinimumTravelTime();
93
+            }
94
+
95
+            @Override
96
+            public int getMaximumSpeed() {
97
+                return GraphStatistics.NO_MAXIMUM_SPEED;
98
+            }
99
+
100
+            @Override
101
+            public Mode getMode() {
102
+                return Mode.TIME;
103
+            }
104
+
105
+            @Override
106
+            public String toString() {
107
+                return "Fastest path, only roads open for cars";
108
+            }
109
+        });
110
+
111
+        // Non-private roads for pedestrian and bicycle:
112
+        filters.add(new ArcInspector() {
113
+
114
+            @Override
115
+            public boolean isAllowed(Arc arc) {
116
+                return arc.getRoadInformation().getAccessRestrictions()
117
+                        .isAllowedForAny(AccessMode.FOOT, EnumSet.complementOf(EnumSet
118
+                                .of(AccessRestriction.FORBIDDEN, AccessRestriction.PRIVATE)));
119
+            }
120
+
121
+            @Override
122
+            public double getCost(Arc arc) {
123
+                return arc.getTravelTime(
124
+                        Math.min(getMaximumSpeed(), arc.getRoadInformation().getMaximumSpeed()));
125
+            }
126
+
127
+            @Override
128
+            public String toString() {
129
+                return "Fastest path for pedestrian";
130
+            }
131
+
132
+            @Override
133
+            public int getMaximumSpeed() {
134
+                return 5;
135
+            }
136
+
137
+            @Override
138
+            public Mode getMode() {
139
+                return Mode.TIME;
140
+            }
141
+        });
142
+
143
+        // Add your own filters here (do not forget to implement toString()
144
+        // to get an understandable output!):
145
+
146
+        return filters;
147
+    }
148
+
149
+}

+ 3
- 2
src/main/org/insa/algo/carpooling/CarPoolingData.java View File

@@ -1,12 +1,13 @@
1 1
 package org.insa.algo.carpooling;
2 2
 
3 3
 import org.insa.algo.AbstractInputData;
4
+import org.insa.algo.ArcInspector;
4 5
 import org.insa.graph.Graph;
5 6
 
6 7
 public class CarPoolingData extends AbstractInputData {
7 8
 
8
-    protected CarPoolingData(Graph graph, Mode mode, ArcFilter arcFilter) {
9
-        super(graph, mode, arcFilter);
9
+    protected CarPoolingData(Graph graph, ArcInspector arcFilter) {
10
+        super(graph, arcFilter);
10 11
     }
11 12
 
12 13
 }

+ 3
- 2
src/main/org/insa/algo/packageswitch/PackageSwitchData.java View File

@@ -1,12 +1,13 @@
1 1
 package org.insa.algo.packageswitch;
2 2
 
3 3
 import org.insa.algo.AbstractInputData;
4
+import org.insa.algo.ArcInspector;
4 5
 import org.insa.graph.Graph;
5 6
 
6 7
 public class PackageSwitchData extends AbstractInputData {
7 8
 
8
-    protected PackageSwitchData(Graph graph, Mode mode, ArcFilter arcFilter) {
9
-        super(graph, mode, arcFilter);
9
+    protected PackageSwitchData(Graph graph, ArcInspector arcFilter) {
10
+        super(graph, arcFilter);
10 11
     }
11 12
 
12 13
 }

+ 83
- 86
src/main/org/insa/algo/shortestpath/BellmanFordAlgorithm.java View File

@@ -4,7 +4,6 @@ import java.util.ArrayList;
4 4
 import java.util.Arrays;
5 5
 import java.util.Collections;
6 6
 
7
-import org.insa.algo.AbstractInputData;
8 7
 import org.insa.algo.AbstractSolution.Status;
9 8
 import org.insa.graph.Arc;
10 9
 import org.insa.graph.Graph;
@@ -13,90 +12,88 @@ import org.insa.graph.Path;
13 12
 
14 13
 public class BellmanFordAlgorithm extends ShortestPathAlgorithm {
15 14
 
16
-    public BellmanFordAlgorithm(ShortestPathData data) {
17
-        super(data);
18
-    }
19
-
20
-    @Override
21
-    protected ShortestPathSolution doRun() {
22
-
23
-        // Retrieve the graph.
24
-        ShortestPathData data = getInputData();
25
-        Graph graph = data.getGraph();
26
-
27
-        final int nbNodes = graph.size();
28
-
29
-        // Initialize array of distances.
30
-        double[] distances = new double[nbNodes];
31
-        Arrays.fill(distances, Double.POSITIVE_INFINITY);
32
-        distances[data.getOrigin().getId()] = 0;
33
-
34
-        // Notify observers about the first event (origin processed).
35
-        notifyOriginProcessed(data.getOrigin());
36
-
37
-        // Initialize array of predecessors.
38
-        Arc[] predecessorArcs = new Arc[nbNodes];
39
-
40
-        // Actual algorithm, we will assume the graph does not contain negative cycle...
41
-        boolean found = false;
42
-        for (int i = 0; !found && i < nbNodes; ++i) {
43
-            found = true;
44
-            for (Node node: graph) {
45
-                for (Arc arc: node) {
46
-
47
-                    // Small test to check allowed roads...
48
-                    if (!data.isAllowed(arc)) {
49
-                        continue;
50
-                    }
51
-
52
-                    // Retrieve weight of the arc.
53
-                    double w = data.getMode() == AbstractInputData.Mode.LENGTH ? arc.getLength()
54
-                            : arc.getMinimumTravelTime();
55
-
56
-                    double oldDistance = distances[arc.getDestination().getId()];
57
-                    double newDistance = distances[node.getId()] + w;
58
-
59
-                    if (Double.isInfinite(oldDistance) && Double.isFinite(newDistance)) {
60
-                        notifyNodeReached(arc.getDestination());
61
-                    }
62
-
63
-                    // Check if new distances would be better, if so update...
64
-                    if (newDistance < oldDistance) {
65
-                        found = false;
66
-                        distances[arc.getDestination().getId()] = distances[node.getId()] + w;
67
-                        predecessorArcs[arc.getDestination().getId()] = arc;
68
-                    }
69
-                }
70
-            }
71
-        }
72
-
73
-        ShortestPathSolution solution = null;
74
-
75
-        // Destination has no predecessor, the solution is infeasible...
76
-        if (predecessorArcs[data.getDestination().getId()] == null) {
77
-            solution = new ShortestPathSolution(data, Status.INFEASIBLE);
78
-        }
79
-        else {
80
-
81
-            // The destination has been found, notify the observers.
82
-            notifyDestinationReached(data.getDestination());
83
-
84
-            // Create the path from the array of predecessors...
85
-            ArrayList<Arc> arcs = new ArrayList<>();
86
-            Arc arc = predecessorArcs[data.getDestination().getId()];
87
-            while (arc != null) {
88
-                arcs.add(arc);
89
-                arc = predecessorArcs[arc.getOrigin().getId()];
90
-            }
91
-
92
-            // Reverse the path...
93
-            Collections.reverse(arcs);
94
-
95
-            // Create the final solution.
96
-            solution = new ShortestPathSolution(data, Status.OPTIMAL, new Path(graph, arcs));
97
-        }
98
-
99
-        return solution;
100
-    }
15
+	public BellmanFordAlgorithm(ShortestPathData data) {
16
+		super(data);
17
+	}
18
+
19
+	@Override
20
+	protected ShortestPathSolution doRun() {
21
+
22
+		// Retrieve the graph.
23
+		ShortestPathData data = getInputData();
24
+		Graph graph = data.getGraph();
25
+
26
+		final int nbNodes = graph.size();
27
+
28
+		// Initialize array of distances.
29
+		double[] distances = new double[nbNodes];
30
+		Arrays.fill(distances, Double.POSITIVE_INFINITY);
31
+		distances[data.getOrigin().getId()] = 0;
32
+
33
+		// Notify observers about the first event (origin processed).
34
+		notifyOriginProcessed(data.getOrigin());
35
+
36
+		// Initialize array of predecessors.
37
+		Arc[] predecessorArcs = new Arc[nbNodes];
38
+
39
+		// Actual algorithm, we will assume the graph does not contain negative
40
+		// cycle...
41
+		boolean found = false;
42
+		for (int i = 0; !found && i < nbNodes; ++i) {
43
+			found = true;
44
+			for (Node node : graph) {
45
+				for (Arc arc : node) {
46
+
47
+					// Small test to check allowed roads...
48
+					if (!data.isAllowed(arc)) {
49
+						continue;
50
+					}
51
+
52
+					// Retrieve weight of the arc.
53
+					double w = data.getCost(arc);
54
+					double oldDistance = distances[arc.getDestination().getId()];
55
+					double newDistance = distances[node.getId()] + w;
56
+
57
+					if (Double.isInfinite(oldDistance) && Double.isFinite(newDistance)) {
58
+						notifyNodeReached(arc.getDestination());
59
+					}
60
+
61
+					// Check if new distances would be better, if so update...
62
+					if (newDistance < oldDistance) {
63
+						found = false;
64
+						distances[arc.getDestination().getId()] = distances[node.getId()] + w;
65
+						predecessorArcs[arc.getDestination().getId()] = arc;
66
+					}
67
+				}
68
+			}
69
+		}
70
+
71
+		ShortestPathSolution solution = null;
72
+
73
+		// Destination has no predecessor, the solution is infeasible...
74
+		if (predecessorArcs[data.getDestination().getId()] == null) {
75
+			solution = new ShortestPathSolution(data, Status.INFEASIBLE);
76
+		} else {
77
+
78
+			// The destination has been found, notify the observers.
79
+			notifyDestinationReached(data.getDestination());
80
+
81
+			// Create the path from the array of predecessors...
82
+			ArrayList<Arc> arcs = new ArrayList<>();
83
+			Arc arc = predecessorArcs[data.getDestination().getId()];
84
+			while (arc != null) {
85
+				arcs.add(arc);
86
+				arc = predecessorArcs[arc.getOrigin().getId()];
87
+			}
88
+
89
+			// Reverse the path...
90
+			Collections.reverse(arcs);
91
+
92
+			// Create the final solution.
93
+			solution = new ShortestPathSolution(data, Status.OPTIMAL, new Path(graph, arcs));
94
+		}
95
+
96
+		return solution;
97
+	}
101 98
 
102 99
 }

+ 6
- 22
src/main/org/insa/algo/shortestpath/ShortestPathData.java View File

@@ -1,6 +1,7 @@
1 1
 package org.insa.algo.shortestpath;
2 2
 
3 3
 import org.insa.algo.AbstractInputData;
4
+import org.insa.algo.ArcInspector;
4 5
 import org.insa.graph.Graph;
5 6
 import org.insa.graph.Node;
6 7
 
@@ -10,33 +11,16 @@ public class ShortestPathData extends AbstractInputData {
10 11
     private final Node origin, destination;
11 12
 
12 13
     /**
13
-     * Construct a new instance of ShortestPathData with the given parameters and
14
-     * for which all arcs are allowed.
15
-     * 
16
-     * @param graph Graph in which the path should be looked for.
17
-     * @param origin Origin node of the path.
18
-     * @param destination Destination node of the path.
19
-     * @param mode Cost mode for the path.
20
-     */
21
-    public ShortestPathData(Graph graph, Node origin, Node destination, Mode mode) {
22
-        super(graph, mode);
23
-        this.origin = origin;
24
-        this.destination = destination;
25
-    }
26
-
27
-    /**
28 14
      * Construct a new instance of ShortestPathInputData with the given parameters.
29 15
      * 
30 16
      * @param graph Graph in which the path should be looked for.
31 17
      * @param origin Origin node of the path.
32 18
      * @param destination Destination node of the path.
33
-     * @param mode Cost mode for the path.
34
-     * @param arcFilter Filter for arcs (used to allow only a specific set of arcs
35
-     *        in the graph to be used).
19
+     * @param arcInspector Filter for arcs (used to allow only a specific set of
20
+     *        arcs in the graph to be used).
36 21
      */
37
-    public ShortestPathData(Graph graph, Node origin, Node destination, Mode mode,
38
-            AbstractInputData.ArcFilter arcFilter) {
39
-        super(graph, mode, arcFilter);
22
+    public ShortestPathData(Graph graph, Node origin, Node destination, ArcInspector arcInspector) {
23
+        super(graph, arcInspector);
40 24
         this.origin = origin;
41 25
         this.destination = destination;
42 26
     }
@@ -58,6 +42,6 @@ public class ShortestPathData extends AbstractInputData {
58 42
     @Override
59 43
     public String toString() {
60 44
         return "Shortest-path from #" + origin.getId() + " to #" + destination.getId() + " ["
61
-                + getMode().toString().toLowerCase() + "]";
45
+                + this.arcInspector.toString().toLowerCase() + "]";
62 46
     }
63 47
 }

+ 9
- 5
src/main/org/insa/algo/shortestpath/ShortestPathSolution.java View File

@@ -1,7 +1,8 @@
1 1
 package org.insa.algo.shortestpath;
2 2
 
3
-import org.insa.algo.AbstractInputData;
3
+import org.insa.algo.AbstractInputData.Mode;
4 4
 import org.insa.algo.AbstractSolution;
5
+import org.insa.graph.Arc;
5 6
 import org.insa.graph.Path;
6 7
 
7 8
 public class ShortestPathSolution extends AbstractSolution {
@@ -59,14 +60,17 @@ public class ShortestPathSolution extends AbstractSolution {
59 60
                     getInputData().getOrigin().getId(), getInputData().getDestination().getId());
60 61
         }
61 62
         else {
63
+            double cost = 0;
64
+            for (Arc arc: getPath().getArcs()) {
65
+                cost += getInputData().getCost(arc);
66
+            }
62 67
             info = String.format("Found a path from node #%d to node #%d",
63 68
                     getInputData().getOrigin().getId(), getInputData().getDestination().getId());
64
-            if (getInputData().getMode() == AbstractInputData.Mode.LENGTH) {
65
-                info = String.format("%s, %.4f kilometers", info, (getPath().getLength() / 1000.0));
69
+            if (getInputData().getMode() == Mode.LENGTH) {
70
+                info = String.format("%s, %.4f kilometers", info, cost / 1000.0);
66 71
             }
67 72
             else {
68
-                info = String.format("%s, %.4f minutes", info,
69
-                        (getPath().getMinimumTravelTime() / 60.0));
73
+                info = String.format("%s, %.4f minutes", info, cost / 60.0);
70 74
             }
71 75
         }
72 76
         info += " in " + getSolvingTime().getSeconds() + " seconds.";

+ 13
- 39
src/main/org/insa/algo/utils/BinaryHeap.java View File

@@ -18,14 +18,13 @@ import java.util.ArrayList;
18 18
  * @author Mark Allen Weiss
19 19
  * @author DLB
20 20
  */
21
-public class BinaryHeap<E extends Comparable<E>> {
21
+public class BinaryHeap<E extends Comparable<E>> implements PriorityQueue<E> {
22 22
 
23 23
     // Number of elements in heap.
24 24
     private int currentSize;
25 25
 
26
-    // The heap array. Java genericity does not work with arrays so we have to use
27
-    // an ArrayList.
28
-    private ArrayList<E> array;
26
+    // The heap array.
27
+    private final ArrayList<E> array;
29 28
 
30 29
     /**
31 30
      * Construct a new empty binary heap.
@@ -126,62 +125,37 @@ public class BinaryHeap<E extends Comparable<E>> {
126 125
         }
127 126
     }
128 127
 
129
-    /**
130
-     * @return true if the heap is empty, false otherwise.
131
-     */
128
+    @Override
132 129
     public boolean isEmpty() {
133 130
         return this.currentSize == 0;
134 131
     }
135 132
 
136
-    /**
137
-     * @return Current size (number of elements) of this heap.
138
-     */
133
+    @Override
139 134
     public int size() {
140 135
         return this.currentSize;
141 136
     }
142 137
 
143
-    /**
144
-     * Insert the given element into the heap.
145
-     * 
146
-     * @param x Item to insert.
147
-     */
148
-    public void add(E x) {
138
+    @Override
139
+    public void insert(E x) {
149 140
         int index = this.currentSize++;
150 141
         this.arraySet(index, x);
151 142
         this.percolateUp(index);
152 143
     }
153 144
 
154
-    /**
155
-     * Tell the binary heap that the given element has been modified and should be
156
-     * re-positioned inside the heap.
157
-     * 
158
-     * @param x Item to update.
159
-     */
160
-    public void update(E x) {
145
+    @Override
146
+    public void remove(E x) throws ElementNotFoundException {
161 147
         // TODO:
162 148
     }
163 149
 
164
-    /**
165
-     * Find the smallest item in the heap.
166
-     * 
167
-     * @return The smallest item in the heap.
168
-     * 
169
-     * @throws RuntimeException if this heap is empty.
170
-     */
171
-    public E findMin() throws RuntimeException {
150
+    @Override
151
+    public E findMin() throws EmptyPriorityQueueException {
172 152
         if (isEmpty())
173 153
             throw new RuntimeException("Empty binary heap.");
174 154
         return this.array.get(0);
175 155
     }
176 156
 
177
-    /**
178
-     * Remove the smallest item from the heap.
179
-     * 
180
-     * @return The smallest item in the heap.
181
-     * 
182
-     * @throws RuntimeException if this heap is empty.
183
-     */
184
-    public E deleteMin() throws RuntimeException {
157
+    @Override
158
+    public E deleteMin() throws EmptyPriorityQueueException {
185 159
         E minItem = findMin();
186 160
         E lastItem = this.array.get(--this.currentSize);
187 161
         this.arraySet(0, lastItem);

+ 64
- 0
src/main/org/insa/algo/utils/BinarySearchTree.java View File

@@ -0,0 +1,64 @@
1
+package org.insa.algo.utils;
2
+
3
+import java.util.SortedSet;
4
+import java.util.TreeSet;
5
+
6
+public class BinarySearchTree<E extends Comparable<E>> implements PriorityQueue<E> {
7
+
8
+    // Underlying implementation
9
+    private final SortedSet<E> sortedSet;
10
+
11
+    /**
12
+     * Create a new empty binary search tree.
13
+     */
14
+    public BinarySearchTree() {
15
+        this.sortedSet = new TreeSet<>();
16
+    }
17
+
18
+    /**
19
+     * Create a copy of the given binary search tree.
20
+     * 
21
+     * @param bst Binary search tree to copy.
22
+     */
23
+    public BinarySearchTree(BinarySearchTree<E> bst) {
24
+        this.sortedSet = new TreeSet<>(bst.sortedSet);
25
+    }
26
+
27
+    @Override
28
+    public boolean isEmpty() {
29
+        return sortedSet.isEmpty();
30
+    }
31
+
32
+    @Override
33
+    public int size() {
34
+        return sortedSet.size();
35
+    }
36
+
37
+    @Override
38
+    public void insert(E x) {
39
+        sortedSet.add(x);
40
+    }
41
+
42
+    @Override
43
+    public void remove(E x) throws ElementNotFoundException {
44
+        if (!sortedSet.remove(x)) {
45
+            throw new ElementNotFoundException(x);
46
+        }
47
+    }
48
+
49
+    @Override
50
+    public E findMin() throws EmptyPriorityQueueException {
51
+        if (isEmpty()) {
52
+            throw new EmptyPriorityQueueException();
53
+        }
54
+        return sortedSet.first();
55
+    }
56
+
57
+    @Override
58
+    public E deleteMin() throws EmptyPriorityQueueException {
59
+        E min = findMin();
60
+        remove(min);
61
+        return min;
62
+    }
63
+
64
+}

+ 32
- 0
src/main/org/insa/algo/utils/ElementNotFoundException.java View File

@@ -0,0 +1,32 @@
1
+package org.insa.algo.utils;
2
+
3
+public class ElementNotFoundException extends RuntimeException {
4
+
5
+    /**
6
+     * 
7
+     */
8
+    private static final long serialVersionUID = 1L;
9
+
10
+    // Element not found
11
+    private final Object element;
12
+
13
+    /**
14
+     * @param element Element that was not found.
15
+     */
16
+    public ElementNotFoundException(Object element) {
17
+        this.element = element;
18
+    }
19
+
20
+    /**
21
+     * @return The element that was not found.
22
+     */
23
+    public Object getElement() {
24
+        return this.element;
25
+    }
26
+
27
+    @Override
28
+    public String toString() {
29
+        return "element not found: " + element;
30
+    }
31
+
32
+}

+ 16
- 0
src/main/org/insa/algo/utils/EmptyPriorityQueueException.java View File

@@ -0,0 +1,16 @@
1
+package org.insa.algo.utils;
2
+
3
+public class EmptyPriorityQueueException extends RuntimeException {
4
+
5
+    /**
6
+     * 
7
+     */
8
+    private static final long serialVersionUID = 1L;
9
+
10
+    /**
11
+     * 
12
+     */
13
+    public EmptyPriorityQueueException() {
14
+    }
15
+
16
+}

+ 54
- 0
src/main/org/insa/algo/utils/PriorityQueue.java View File

@@ -0,0 +1,54 @@
1
+package org.insa.algo.utils;
2
+
3
+/**
4
+ * Interface representing a basic priority queue.
5
+ * 
6
+ * @see https://en.wikipedia.org/wiki/Priority_queue
7
+ */
8
+public interface PriorityQueue<E extends Comparable<E>> {
9
+
10
+    /**
11
+     * Check if the priority queue is empty.
12
+     * 
13
+     * @return true if the queue is empty, false otherwise.
14
+     */
15
+    public boolean isEmpty();
16
+
17
+    /**
18
+     * @return Current size (number of elements) of this queue.
19
+     */
20
+    public int size();
21
+
22
+    /**
23
+     * Insert the given element into the queue.
24
+     * 
25
+     * @param x Item to insert.
26
+     */
27
+    public void insert(E x);
28
+
29
+    /**
30
+     * Remove the given element from the priority queue.
31
+     * 
32
+     * @param x Item to remove.
33
+     */
34
+    public void remove(E x) throws ElementNotFoundException;
35
+
36
+    /**
37
+     * Retrieve (but not remove) the smallest item in the queue.
38
+     * 
39
+     * @return The smallest item in the queue.
40
+     * 
41
+     * @throws EmptyPriorityQueueException if this queue is empty.
42
+     */
43
+    public E findMin() throws EmptyPriorityQueueException;
44
+
45
+    /**
46
+     * Remove and return the smallest item from the priority queue.
47
+     * 
48
+     * @return The smallest item in the queue.
49
+     * 
50
+     * @throws EmptyPriorityQueueException if this queue is empty.
51
+     */
52
+    public E deleteMin() throws EmptyPriorityQueueException;
53
+
54
+}

+ 1
- 1
src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsData.java View File

@@ -9,7 +9,7 @@ public class WeaklyConnectedComponentsData extends AbstractInputData {
9 9
      * @param graph Graph for which components should be retrieved.
10 10
      */
11 11
     public WeaklyConnectedComponentsData(Graph graph) {
12
-        super(graph);
12
+        super(graph, null);
13 13
     }
14 14
 
15 15
     @Override

+ 2
- 0
src/main/org/insa/base/Launch.java View File

@@ -23,6 +23,8 @@ public class Launch {
23 23
      * Create a new Drawing inside a JFrame an return it.
24 24
      * 
25 25
      * @return The created drawing.
26
+     * 
27
+     * @throws Exception if something wrong happens when creating the graph.
26 28
      */
27 29
     public static Drawing createDrawing() throws Exception {
28 30
         BasicDrawing basicDrawing = new BasicDrawing();

+ 2
- 0
src/main/org/insa/graph/GraphStatistics.java View File

@@ -94,6 +94,8 @@ public class GraphStatistics {
94 94
         }
95 95
 
96 96
         /**
97
+         * @param other Box to intersect.
98
+         * 
97 99
          * @return true if this box contains the given box.
98 100
          */
99 101
         public boolean contains(BoundingBox other) {

+ 13
- 54
src/main/org/insa/graphics/AlgorithmPanel.java View File

@@ -14,22 +14,18 @@ import java.util.List;
14 14
 
15 15
 import javax.swing.Box;
16 16
 import javax.swing.BoxLayout;
17
-import javax.swing.ButtonGroup;
18 17
 import javax.swing.JButton;
19 18
 import javax.swing.JCheckBox;
20 19
 import javax.swing.JComboBox;
21 20
 import javax.swing.JComponent;
22 21
 import javax.swing.JLabel;
23 22
 import javax.swing.JPanel;
24
-import javax.swing.JRadioButton;
25 23
 import javax.swing.border.EmptyBorder;
26 24
 
27 25
 import org.insa.algo.AbstractAlgorithm;
28
-import org.insa.algo.AbstractInputData;
29
-import org.insa.algo.AbstractInputData.ArcFilter;
30
-import org.insa.algo.AbstractInputData.Mode;
31 26
 import org.insa.algo.AlgorithmFactory;
32
-import org.insa.algo.ArcFilterFactory;
27
+import org.insa.algo.ArcInspector;
28
+import org.insa.algo.ArcInspectorFactory;
33 29
 import org.insa.graph.Node;
34 30
 import org.insa.graphics.NodesInputPanel.InputChangedEvent;
35 31
 import org.insa.graphics.drawing.Drawing;
@@ -55,20 +51,18 @@ public class AlgorithmPanel extends JPanel implements DrawingChangeListener {
55 51
         protected static final int START_EVENT_ID = 0x1;
56 52
 
57 53
         private final List<Node> nodes;
58
-        private final AbstractInputData.Mode mode;
59 54
         private final Class<? extends AbstractAlgorithm<?>> algoClass;
60 55
 
61
-        private final AbstractInputData.ArcFilter arcFilter;
56
+        private final ArcInspector arcFilter;
62 57
 
63 58
         private final boolean graphicVisualization;
64 59
         private final boolean textualVisualization;
65 60
 
66 61
         public StartActionEvent(Class<? extends AbstractAlgorithm<?>> algoClass, List<Node> nodes,
67
-                Mode mode, ArcFilter arcFilter, boolean graphicVisualization,
62
+                ArcInspector arcFilter, boolean graphicVisualization,
68 63
                 boolean textualVisualization) {
69 64
             super(AlgorithmPanel.this, START_EVENT_ID, START_EVENT_COMMAND);
70 65
             this.nodes = nodes;
71
-            this.mode = mode;
72 66
             this.algoClass = algoClass;
73 67
             this.graphicVisualization = graphicVisualization;
74 68
             this.textualVisualization = textualVisualization;
@@ -83,16 +77,9 @@ public class AlgorithmPanel extends JPanel implements DrawingChangeListener {
83 77
         }
84 78
 
85 79
         /**
86
-         * @return Mode associated with this event.
87
-         */
88
-        public Mode getMode() {
89
-            return this.mode;
90
-        }
91
-
92
-        /**
93 80
          * @return Arc filter associated with this event.
94 81
          */
95
-        public ArcFilter getArcFilter() {
82
+        public ArcInspector getArcFilter() {
96 83
             return this.arcFilter;
97 84
         }
98 85
 
@@ -147,16 +134,13 @@ public class AlgorithmPanel extends JPanel implements DrawingChangeListener {
147 134
      * @param baseAlgorithm Base algorithm for this algorithm panel.
148 135
      * @param title Title of the panel.
149 136
      * @param nodeNames Names of the input nodes.
150
-     * @param enableModeSelection <code>true</code> to enable {@link Mode}
151
-     *        selection.
152
-     * @param enableArcFilterSelection <code>true</code> to enable {@link ArcFilter}
153
-     *        selection.
137
+     * @param enableArcFilterSelection <code>true</code> to enable
138
+     *        {@link ArcInspector} selection.
154 139
      * 
155
-     * @see ArcFilterFactory
140
+     * @see ArcInspectorFactory
156 141
      */
157 142
     public AlgorithmPanel(Component parent, Class<? extends AbstractAlgorithm<?>> baseAlgorithm,
158
-            String title, String[] nodeNames, boolean enableModeSelection,
159
-            boolean enableArcFilterSelection) {
143
+            String title, String[] nodeNames, boolean enableArcFilterSelection) {
160 144
         super();
161 145
         setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
162 146
 
@@ -178,20 +162,14 @@ public class AlgorithmPanel extends JPanel implements DrawingChangeListener {
178 162
         add(this.nodesInputPanel);
179 163
         components.add(this.nodesInputPanel);
180 164
 
181
-        JComboBox<ArcFilter> arcFilterSelect = new JComboBox<>(
182
-                ArcFilterFactory.getAllFilters().toArray(new ArcFilter[0]));
165
+        JComboBox<ArcInspector> arcFilterSelect = new JComboBox<>(
166
+                ArcInspectorFactory.getAllFilters().toArray(new ArcInspector[0]));
183 167
         arcFilterSelect.setBackground(Color.WHITE);
184 168
 
185 169
         // Add mode selection
186 170
         JPanel modeAndObserverPanel = new JPanel();
187 171
         modeAndObserverPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
188 172
         modeAndObserverPanel.setLayout(new GridBagLayout());
189
-        JRadioButton lengthModeButton = new JRadioButton("Length");
190
-        lengthModeButton.setSelected(true);
191
-        JRadioButton timeModeButton = new JRadioButton("Time");
192
-        ButtonGroup group = new ButtonGroup();
193
-        group.add(lengthModeButton);
194
-        group.add(timeModeButton);
195 173
 
196 174
         graphicObserverCheckbox = new JCheckBox("Graphic");
197 175
         graphicObserverCheckbox.setSelected(true);
@@ -201,19 +179,6 @@ public class AlgorithmPanel extends JPanel implements DrawingChangeListener {
201 179
 
202 180
         c.fill = GridBagConstraints.HORIZONTAL;
203 181
 
204
-        if (enableModeSelection) {
205
-            c.gridx = 0;
206
-            c.gridy = 0;
207
-            c.weightx = 0;
208
-            modeAndObserverPanel.add(new JLabel("Mode: "), c);
209
-            c.gridx = 1;
210
-            c.weightx = 1;
211
-            modeAndObserverPanel.add(lengthModeButton, c);
212
-            c.gridx = 2;
213
-            c.weightx = 1;
214
-            modeAndObserverPanel.add(timeModeButton, c);
215
-        }
216
-
217 182
         c.gridy = 2;
218 183
         c.gridx = 0;
219 184
         c.weightx = 0;
@@ -236,8 +201,6 @@ public class AlgorithmPanel extends JPanel implements DrawingChangeListener {
236 201
             modeAndObserverPanel.add(arcFilterSelect, c);
237 202
         }
238 203
 
239
-        components.add(timeModeButton);
240
-        components.add(lengthModeButton);
241 204
         components.add(arcFilterSelect);
242 205
         components.add(textualObserverCheckbox);
243 206
 
@@ -258,16 +221,12 @@ public class AlgorithmPanel extends JPanel implements DrawingChangeListener {
258 221
         startAlgoButton.addActionListener(new ActionListener() {
259 222
             @Override
260 223
             public void actionPerformed(ActionEvent e) {
261
-                AbstractInputData.Mode mode = lengthModeButton.isSelected()
262
-                        ? AbstractInputData.Mode.LENGTH
263
-                        : AbstractInputData.Mode.TIME;
264
-
265 224
                 for (ActionListener lis: startActionListeners) {
266 225
                     lis.actionPerformed(new StartActionEvent(
267 226
                             AlgorithmFactory.getAlgorithmClass(baseAlgorithm,
268 227
                                     (String) algoSelect.getSelectedItem()),
269
-                            nodesInputPanel.getNodeForInputs(), mode,
270
-                            (AbstractInputData.ArcFilter) arcFilterSelect.getSelectedItem(),
228
+                            nodesInputPanel.getNodeForInputs(),
229
+                            (ArcInspector) arcFilterSelect.getSelectedItem(),
271 230
                             graphicObserverCheckbox.isSelected(),
272 231
                             textualObserverCheckbox.isSelected()));
273 232
                 }

+ 5
- 6
src/main/org/insa/graphics/MainWindow.java View File

@@ -157,7 +157,7 @@ public class MainWindow extends JFrame {
157 157
         this.currentPalette = this.basicPalette;
158 158
 
159 159
         wccPanel = new AlgorithmPanel(this, WeaklyConnectedComponentsAlgorithm.class,
160
-                "Weakly-Connected Components", new String[] {}, false, false);
160
+                "Weakly-Connected Components", new String[] {}, false);
161 161
         wccPanel.addStartActionListener(new ActionListener() {
162 162
             @Override
163 163
             public void actionPerformed(ActionEvent e) {
@@ -202,13 +202,13 @@ public class MainWindow extends JFrame {
202 202
         });
203 203
 
204 204
         spPanel = new AlgorithmPanel(this, ShortestPathAlgorithm.class, "Shortest-Path",
205
-                new String[] { "Origin", "Destination" }, true, true);
205
+                new String[] { "Origin", "Destination" }, true);
206 206
         spPanel.addStartActionListener(new ActionListener() {
207 207
             @Override
208 208
             public void actionPerformed(ActionEvent e) {
209 209
                 StartActionEvent evt = (StartActionEvent) e;
210 210
                 ShortestPathData data = new ShortestPathData(graph, evt.getNodes().get(0),
211
-                        evt.getNodes().get(1), evt.getMode(), evt.getArcFilter());
211
+                        evt.getNodes().get(1), evt.getArcFilter());
212 212
 
213 213
                 ShortestPathAlgorithm spAlgorithm = null;
214 214
                 try {
@@ -257,11 +257,10 @@ public class MainWindow extends JFrame {
257 257
         cpPanel = new AlgorithmPanel(
258 258
                 this, CarPoolingAlgorithm.class, "Car-Pooling", new String[] { "Origin Car",
259 259
                         "Origin Pedestrian", "Destination Car", "Destination Pedestrian" },
260
-                true, true);
260
+                true);
261 261
 
262 262
         psPanel = new AlgorithmPanel(this, PackageSwitchAlgorithm.class, "Car-Pooling",
263
-                new String[] { "Oribin A", "Origin B", "Destination A", "Destination B" }, true,
264
-                true);
263
+                new String[] { "Oribin A", "Origin B", "Destination A", "Destination B" }, true);
265 264
 
266 265
         // add algorithm panels
267 266
         algoPanels.add(wccPanel);

+ 88
- 36
src/main/org/insa/graphics/drawing/components/BasicDrawing.java View File

@@ -15,7 +15,6 @@ import java.awt.geom.Point2D;
15 15
 import java.awt.image.BufferedImage;
16 16
 import java.io.IOException;
17 17
 import java.util.ArrayList;
18
-import java.util.Collections;
19 18
 import java.util.Iterator;
20 19
 import java.util.List;
21 20
 
@@ -65,6 +64,11 @@ public class BasicDrawing extends JPanel implements Drawing {
65 64
             this.color = color;
66 65
         }
67 66
 
67
+        /**
68
+         * @return The Z level of this overlay (>= 1).
69
+         */
70
+        public abstract int getZLevel();
71
+
68 72
         @Override
69 73
         public void setColor(Color color) {
70 74
             this.color = color;
@@ -88,10 +92,7 @@ public class BasicDrawing extends JPanel implements Drawing {
88 92
 
89 93
         @Override
90 94
         public void delete() {
91
-            synchronized (overlays) {
92
-                BasicDrawing.this.overlays.remove(this);
93
-            }
94
-            BasicDrawing.this.repaint();
95
+            BasicDrawing.this.overlays.remove(this);
95 96
         }
96 97
 
97 98
         /**
@@ -134,6 +135,10 @@ public class BasicDrawing extends JPanel implements Drawing {
134 135
             this.alphaMode = alphaMode;
135 136
         }
136 137
 
138
+        public int getZLevel() {
139
+            return 3;
140
+        }
141
+
137 142
         @Override
138 143
         public Point getPoint() {
139 144
             return point;
@@ -181,6 +186,10 @@ public class BasicDrawing extends JPanel implements Drawing {
181 186
             this.color = color;
182 187
         }
183 188
 
189
+        public int getZLevel() {
190
+            return 2;
191
+        }
192
+
184 193
         @Override
185 194
         public void setColor(Color color) {
186 195
             super.setColor(color);
@@ -243,6 +252,10 @@ public class BasicDrawing extends JPanel implements Drawing {
243 252
             this.graphics.setBackground(new Color(0, 0, 0, 0));
244 253
         }
245 254
 
255
+        public int getZLevel() {
256
+            return 1;
257
+        }
258
+
246 259
         @Override
247 260
         public void setColor(Color color) {
248 261
             super.setColor(color);
@@ -294,6 +307,68 @@ public class BasicDrawing extends JPanel implements Drawing {
294 307
 
295 308
     }
296 309
 
310
+    /**
311
+     * Class encapsulating a set of overlays.
312
+     *
313
+     */
314
+    private class BasicOverlays {
315
+
316
+        // List of overlays.
317
+        private ArrayList<ArrayList<BasicOverlay>> overlays = new ArrayList<>();
318
+
319
+        public synchronized void draw(Graphics2D g) {
320
+            // Clear overlays.
321
+            for (ArrayList<BasicOverlay> arr: this.overlays) {
322
+                for (BasicOverlay overlay: arr) {
323
+                    overlay.draw(g);
324
+                }
325
+            }
326
+        }
327
+
328
+        public synchronized void remove(BasicOverlay overlay) {
329
+            overlays.get(overlay.getZLevel() - 1).remove(overlay);
330
+            BasicDrawing.this.repaint();
331
+        }
332
+
333
+        public void clear() {
334
+            clear(true);
335
+        }
336
+
337
+        public void clear(boolean repaint) {
338
+            // Clear overlays.
339
+            for (ArrayList<BasicOverlay> arr: this.overlays) {
340
+                arr.clear();
341
+            }
342
+            // Repaint if requested.
343
+            if (repaint) {
344
+                BasicDrawing.this.repaint();
345
+            }
346
+        }
347
+
348
+        public BasicOverlay add(BasicOverlay marker) {
349
+            return add(marker, true);
350
+        }
351
+
352
+        public synchronized BasicOverlay add(BasicOverlay overlay, boolean repaint) {
353
+
354
+            // Check if we have a level for this...
355
+            for (int i = overlays.size(); i < overlay.getZLevel(); ++i) {
356
+                overlays.add(new ArrayList<>());
357
+            }
358
+
359
+            // Add overlay to the given list.
360
+            overlays.get(overlay.getZLevel() - 1).add(overlay);
361
+
362
+            // Repaint if requested.
363
+            if (repaint) {
364
+                BasicDrawing.this.repaint();
365
+            }
366
+
367
+            return overlay;
368
+        }
369
+
370
+    };
371
+
297 372
     // Default path color.
298 373
     public static final Color DEFAULT_PATH_COLOR = new Color(66, 134, 244);
299 374
 
@@ -317,8 +392,7 @@ public class BasicDrawing extends JPanel implements Drawing {
317 392
     private Graphics2D graphGraphics = null;
318 393
 
319 394
     // List of image for markers
320
-    private List<BasicOverlay> overlays = Collections
321
-            .synchronizedList(new ArrayList<BasicOverlay>());
395
+    private BasicOverlays overlays = new BasicOverlays();
322 396
 
323 397
     // Mapping DrawingClickListener -> MouseEventListener
324 398
     private List<DrawingClickListener> drawingClickListeners = new ArrayList<>();
@@ -391,11 +465,7 @@ public class BasicDrawing extends JPanel implements Drawing {
391 465
         }
392 466
 
393 467
         // Draw markers
394
-        synchronized (overlays) {
395
-            for (BasicOverlay overlay: overlays) {
396
-                overlay.draw(g);
397
-            }
398
-        }
468
+        this.overlays.draw(g);
399 469
 
400 470
         g.setTransform(sTransform);
401 471
         if (this.zoomControls != null) {
@@ -416,9 +486,7 @@ public class BasicDrawing extends JPanel implements Drawing {
416 486
         if (this.graphGraphics != null) {
417 487
             this.graphGraphics.clearRect(0, 0, this.width, this.height);
418 488
         }
419
-        synchronized (overlays) {
420
-            this.overlays.clear();
421
-        }
489
+        this.overlays.clear(false);
422 490
         this.repaint();
423 491
     }
424 492
 
@@ -429,10 +497,7 @@ public class BasicDrawing extends JPanel implements Drawing {
429 497
      */
430 498
     @Override
431 499
     public void clearOverlays() {
432
-        synchronized (overlays) {
433
-            this.overlays.clear();
434
-        }
435
-        this.repaint();
500
+        this.overlays.clear();
436 501
     }
437 502
 
438 503
     /**
@@ -495,21 +560,12 @@ public class BasicDrawing extends JPanel implements Drawing {
495 560
 
496 561
     @Override
497 562
     public MarkerOverlay drawMarker(Point point, Color outer, Color inner, AlphaMode mode) {
498
-        BasicMarkerOverlay marker = createMarker(point, outer, inner, mode);
499
-        synchronized (overlays) {
500
-            this.overlays.add(marker);
501
-        }
502
-        this.repaint();
503
-        return marker;
563
+        return (MarkerOverlay) this.overlays.add(createMarker(point, outer, inner, mode));
504 564
     }
505 565
 
506 566
     @Override
507 567
     public PointSetOverlay createPointSetOverlay() {
508
-        BasicPointSetOverlay ps = new BasicPointSetOverlay();
509
-        synchronized (overlays) {
510
-            this.overlays.add(ps);
511
-        }
512
-        return ps;
568
+        return (PointSetOverlay) this.overlays.add(new BasicPointSetOverlay(), false);
513 569
     }
514 570
 
515 571
     @Override
@@ -671,12 +727,8 @@ public class BasicDrawing extends JPanel implements Drawing {
671 727
             destination = createMarker(path.getDestination().getPoint(), color, color,
672 728
                     AlphaMode.TRANSPARENT);
673 729
         }
674
-        BasicPathOverlay overlay = new BasicPathOverlay(points, color, origin, destination);
675
-        synchronized (overlays) {
676
-            this.overlays.add(overlay);
677
-        }
678
-        this.repaint();
679
-        return overlay;
730
+        return (PathOverlay) this.overlays
731
+                .add(new BasicPathOverlay(points, color, origin, destination));
680 732
     }
681 733
 
682 734
     @Override

+ 2
- 1
src/main/org/insa/graphics/drawing/overlays/MarkerAutoScaling.java View File

@@ -18,7 +18,8 @@ import org.mapsforge.map.layer.overlay.Marker;
18 18
  * correcting this. Internally, this image stores an {@link Image} instance and
19 19
  * scale it when a redraw is requested.
20 20
  * 
21
- * @see MarkerUtils#getMarkerForColor(java.awt.Color)
21
+ * @see MarkerUtils#getMarkerForColor(java.awt.Color, java.awt.Color,
22
+ *      org.insa.graphics.drawing.Drawing.AlphaMode)
22 23
  * @see PaintUtils#getStrokeWidth(int, byte)
23 24
  */
24 25
 public class MarkerAutoScaling extends Marker {

+ 0
- 2
src/main/org/insa/graphics/drawing/overlays/MarkerUtils.java View File

@@ -18,8 +18,6 @@ public class MarkerUtils {
18 18
      * @param mode Mode to use to fill the inner part of the marker.
19 19
      * 
20 20
      * @return An image representing a marker.
21
-     * 
22
-     * @see MarkerUtils#getMarkerForColor(Color, AlphaMode)
23 21
      */
24 22
     public static Image getMarkerForColor(Color outer, Color inner, AlphaMode mode) {
25 23
         // create image

+ 88
- 19
src/test/org/insa/algo/utils/BinaryHeapTest.java View File

@@ -1,6 +1,7 @@
1 1
 package org.insa.algo.utils;
2 2
 
3 3
 import static org.junit.Assert.assertEquals;
4
+import static org.junit.Assert.assertFalse;
4 5
 import static org.junit.Assert.assertTrue;
5 6
 
6 7
 import java.util.Arrays;
@@ -59,46 +60,78 @@ public class BinaryHeapTest {
59 60
         this.heap2 = new BinaryHeap<>();
60 61
 
61 62
         for (MutableInteger v: data1) {
62
-            this.heap1.add(v);
63
+            this.heap1.insert(v);
63 64
         }
64 65
 
65 66
         for (MutableInteger v: data2) {
66
-            this.heap2.add(v);
67
+            this.heap2.insert(v);
67 68
         }
68 69
     }
69 70
 
70 71
     @Test
72
+    public void testIsEmpty() {
73
+        BinaryHeap<MutableInteger> tree = new BinaryHeap<>();
74
+        assertTrue(tree.isEmpty());
75
+        assertFalse(this.heap1.isEmpty());
76
+        assertFalse(this.heap2.isEmpty());
77
+    }
78
+
79
+    @Test
80
+    public void testSize() {
81
+        BinaryHeap<MutableInteger> tree = new BinaryHeap<>();
82
+        assertEquals(0, tree.size());
83
+        assertEquals(20, this.heap1.size());
84
+        assertEquals(7, this.heap2.size());
85
+    }
86
+
87
+    @Test
71 88
     public void testInsert() {
72 89
         BinaryHeap<MutableInteger> heap = new BinaryHeap<>();
73 90
         int size = 0;
74 91
         for (MutableInteger x: data1) {
75
-            heap.add(x);
76
-            size += 1;
77
-            assertEquals(heap.size(), size);
92
+            heap.insert(x);
93
+            assertEquals(++size, heap.size());
78 94
         }
79 95
         assertEquals(data1.length, heap.size());
80 96
 
81 97
         heap = new BinaryHeap<>();
82 98
         size = 0;
83 99
         for (MutableInteger x: data2) {
84
-            heap.add(x);
85
-            size += 1;
86
-            assertEquals(heap.size(), size);
100
+            heap.insert(x);
101
+            assertEquals(++size, heap.size());
87 102
         }
88 103
         assertEquals(data2.length, heap.size());
89 104
     }
90 105
 
106
+    @Test(expected = EmptyPriorityQueueException.class)
107
+    public void testEmptyFindMin() {
108
+        BinaryHeap<MutableInteger> heap = new BinaryHeap<>();
109
+        heap.findMin();
110
+    }
111
+
112
+    @Test
113
+    public void testFindMin() {
114
+        assertEquals(0, heap1.findMin().get());
115
+        assertEquals(1, heap2.findMin().get());
116
+    }
117
+
118
+    @Test(expected = EmptyPriorityQueueException.class)
119
+    public void testEmptyDeleteMin() {
120
+        BinaryHeap<MutableInteger> heap = new BinaryHeap<>();
121
+        heap.deleteMin();
122
+    }
123
+
91 124
     @Test
92 125
     public void testDeleteMin() {
93 126
         // range 1 (sorted)
94 127
         int size = data1.length;
95 128
         assertEquals(heap1.size(), size);
96 129
         for (MutableInteger x: data1) {
97
-            assertEquals(heap1.deleteMin(), x);
130
+            assertEquals(x, heap1.deleteMin());
98 131
             size -= 1;
99
-            assertEquals(heap1.size(), size);
132
+            assertEquals(size, heap1.size());
100 133
         }
101
-        assertEquals(heap1.size(), 0);
134
+        assertEquals(0, heap1.size());
102 135
         assertTrue(heap1.isEmpty());
103 136
 
104 137
         // range 2 (was not sorted)
@@ -107,20 +140,56 @@ public class BinaryHeapTest {
107 140
         size = range2.length;
108 141
         assertEquals(heap2.size(), size);
109 142
         for (MutableInteger x: range2) {
110
-            assertEquals(heap2.deleteMin().get(), x.get());
143
+            assertEquals(x.get(), heap2.deleteMin().get());
111 144
             size -= 1;
112
-            assertEquals(heap2.size(), size);
145
+            assertEquals(size, heap2.size());
146
+        }
147
+        assertEquals(0, heap2.size());
148
+        assertTrue(heap2.isEmpty());
149
+    }
150
+
151
+    @Test(expected = ElementNotFoundException.class)
152
+    public void testRemoveEmpty() {
153
+        BinaryHeap<MutableInteger> heap = new BinaryHeap<>();
154
+        heap.remove(new MutableInteger(0));
155
+    }
156
+
157
+    @Test(expected = ElementNotFoundException.class)
158
+    public void testRemoveNotFound() {
159
+        heap1.remove(new MutableInteger(20));
160
+    }
161
+
162
+    @Test
163
+    public void testRemove() {
164
+        // heap 1
165
+        int size1 = heap1.size();
166
+        int[] deleteOrder1 = new int[] { 12, 17, 18, 19, 4, 5, 3, 2, 0, 9, 10, 16, 8, 14, 13, 15, 7,
167
+                6, 1, 11 };
168
+        for (int x: deleteOrder1) {
169
+            heap1.remove(this.data1[x]);
170
+            assertEquals(--size1, heap1.size());
171
+        }
172
+        assertTrue(heap1.isEmpty());
173
+
174
+        // heap 2
175
+        int size2 = heap2.size();
176
+        int[] deleteOrder2 = new int[] { 6, 5, 0, 1, 4, 2, 3 };
177
+        for (int x: deleteOrder2) {
178
+            heap2.remove(this.data2[x]);
179
+            assertEquals(--size2, heap2.size());
113 180
         }
114
-        assertEquals(heap2.size(), 0);
115 181
         assertTrue(heap2.isEmpty());
116 182
     }
117 183
 
118 184
     @Test
119
-    public void testUpdate() {
120
-        MutableInteger newMin = data2[data2.length - 1];
121
-        newMin.set(0);
122
-        heap2.update(newMin);
123
-        assertEquals(heap2.findMin(), newMin);
185
+    public void testRemoveThenAdd() {
186
+        MutableInteger mi5 = this.data1[6];
187
+        heap1.remove(mi5);
188
+        assertEquals(19, heap1.size());
189
+        mi5.set(-20);
190
+        heap1.insert(mi5);
191
+        assertEquals(20, heap1.size());
192
+        assertEquals(-20, heap1.findMin().get());
124 193
     }
125 194
 
126 195
 }

+ 195
- 0
src/test/org/insa/algo/utils/BinarySearchTreeTest.java View File

@@ -0,0 +1,195 @@
1
+package org.insa.algo.utils;
2
+
3
+import static org.junit.Assert.assertEquals;
4
+import static org.junit.Assert.assertFalse;
5
+import static org.junit.Assert.assertTrue;
6
+
7
+import java.util.Arrays;
8
+import java.util.stream.IntStream;
9
+
10
+import org.junit.Before;
11
+import org.junit.Test;
12
+
13
+public class BinarySearchTreeTest {
14
+
15
+    class MutableInteger implements Comparable<MutableInteger> {
16
+
17
+        // Actual value
18
+        private int value;
19
+
20
+        public MutableInteger(int value) {
21
+            this.value = value;
22
+        }
23
+
24
+        /**
25
+         * @return The integer value stored inside this MutableInteger.
26
+         */
27
+        public int get() {
28
+            return this.value;
29
+        }
30
+
31
+        /**
32
+         * Update the integer value stored inside this MutableInteger.
33
+         * 
34
+         * @param value New value to set.
35
+         */
36
+        public void set(int value) {
37
+            this.value = value;
38
+        }
39
+
40
+        @Override
41
+        public int compareTo(MutableInteger other) {
42
+            return Integer.compare(this.value, other.value);
43
+        }
44
+
45
+    };
46
+
47
+    // Raw data arrays.
48
+    private MutableInteger[] data1 = IntStream.range(0, 20).mapToObj(MutableInteger::new)
49
+            .toArray(MutableInteger[]::new);
50
+    private MutableInteger[] data2 = Arrays.stream(new int[] { 8, 1, 6, 3, 4, 5, 9 })
51
+            .mapToObj(MutableInteger::new).toArray(MutableInteger[]::new);
52
+
53
+    // Actual searchTree.
54
+    private BinarySearchTree<MutableInteger> searchTree1, searchTree2;
55
+
56
+    @Before
57
+    public void init() {
58
+        // Create the range searchTree
59
+        this.searchTree1 = new BinarySearchTree<>();
60
+        this.searchTree2 = new BinarySearchTree<>();
61
+
62
+        for (MutableInteger v: data1) {
63
+            this.searchTree1.insert(v);
64
+        }
65
+
66
+        for (MutableInteger v: data2) {
67
+            this.searchTree2.insert(v);
68
+        }
69
+    }
70
+
71
+    @Test
72
+    public void testIsEmpty() {
73
+        BinarySearchTree<MutableInteger> tree = new BinarySearchTree<>();
74
+        assertTrue(tree.isEmpty());
75
+        assertFalse(this.searchTree1.isEmpty());
76
+        assertFalse(this.searchTree2.isEmpty());
77
+    }
78
+
79
+    @Test
80
+    public void testSize() {
81
+        BinarySearchTree<MutableInteger> tree = new BinarySearchTree<>();
82
+        assertEquals(0, tree.size());
83
+        assertEquals(20, this.searchTree1.size());
84
+        assertEquals(7, this.searchTree2.size());
85
+    }
86
+
87
+    @Test
88
+    public void testInsert() {
89
+        BinarySearchTree<MutableInteger> searchTree = new BinarySearchTree<>();
90
+        int size = 0;
91
+        for (MutableInteger x: data1) {
92
+            searchTree.insert(x);
93
+            assertEquals(++size, searchTree.size());
94
+        }
95
+        assertEquals(data1.length, searchTree.size());
96
+
97
+        searchTree = new BinarySearchTree<>();
98
+        size = 0;
99
+        for (MutableInteger x: data2) {
100
+            searchTree.insert(x);
101
+            assertEquals(++size, searchTree.size());
102
+        }
103
+        assertEquals(data2.length, searchTree.size());
104
+    }
105
+
106
+    @Test(expected = EmptyPriorityQueueException.class)
107
+    public void testEmptyFindMin() {
108
+        BinarySearchTree<MutableInteger> searchTree = new BinarySearchTree<>();
109
+        searchTree.findMin();
110
+    }
111
+
112
+    @Test
113
+    public void testFindMin() {
114
+        assertEquals(0, searchTree1.findMin().get());
115
+        assertEquals(1, searchTree2.findMin().get());
116
+    }
117
+
118
+    @Test(expected = EmptyPriorityQueueException.class)
119
+    public void testEmptyDeleteMin() {
120
+        BinarySearchTree<MutableInteger> searchTree = new BinarySearchTree<>();
121
+        searchTree.deleteMin();
122
+    }
123
+
124
+    @Test
125
+    public void testDeleteMin() {
126
+        // range 1 (sorted)
127
+        int size = data1.length;
128
+        assertEquals(searchTree1.size(), size);
129
+        for (MutableInteger x: data1) {
130
+            assertEquals(x, searchTree1.deleteMin());
131
+            size -= 1;
132
+            assertEquals(size, searchTree1.size());
133
+        }
134
+        assertEquals(0, searchTree1.size());
135
+        assertTrue(searchTree1.isEmpty());
136
+
137
+        // range 2 (was not sorted)
138
+        MutableInteger[] range2 = Arrays.copyOf(data2, data2.length);
139
+        Arrays.sort(range2);
140
+        size = range2.length;
141
+        assertEquals(searchTree2.size(), size);
142
+        for (MutableInteger x: range2) {
143
+            assertEquals(x.get(), searchTree2.deleteMin().get());
144
+            size -= 1;
145
+            assertEquals(size, searchTree2.size());
146
+        }
147
+        assertEquals(0, searchTree2.size());
148
+        assertTrue(searchTree2.isEmpty());
149
+    }
150
+
151
+    @Test(expected = ElementNotFoundException.class)
152
+    public void testRemoveEmpty() {
153
+        BinarySearchTree<MutableInteger> searchTree = new BinarySearchTree<>();
154
+        searchTree.remove(new MutableInteger(0));
155
+    }
156
+
157
+    @Test(expected = ElementNotFoundException.class)
158
+    public void testRemoveNotFound() {
159
+        searchTree1.remove(new MutableInteger(20));
160
+    }
161
+
162
+    @Test
163
+    public void testRemove() {
164
+        // searchTree 1
165
+        int size1 = searchTree1.size();
166
+        int[] deleteOrder1 = new int[] { 12, 17, 18, 19, 4, 5, 3, 2, 0, 9, 10, 16, 8, 14, 13, 15, 7,
167
+                6, 1, 11 };
168
+        for (int x: deleteOrder1) {
169
+            searchTree1.remove(this.data1[x]);
170
+            assertEquals(--size1, searchTree1.size());
171
+        }
172
+        assertTrue(searchTree1.isEmpty());
173
+
174
+        // searchTree 2
175
+        int size2 = searchTree2.size();
176
+        int[] deleteOrder2 = new int[] { 6, 5, 0, 1, 4, 2, 3 };
177
+        for (int x: deleteOrder2) {
178
+            searchTree2.remove(this.data2[x]);
179
+            assertEquals(--size2, searchTree2.size());
180
+        }
181
+        assertTrue(searchTree2.isEmpty());
182
+    }
183
+
184
+    @Test
185
+    public void testRemoveThenAdd() {
186
+        MutableInteger mi5 = this.data1[6];
187
+        searchTree1.remove(mi5);
188
+        assertEquals(19, searchTree1.size());
189
+        mi5.set(-20);
190
+        searchTree1.insert(mi5);
191
+        assertEquals(20, searchTree1.size());
192
+        assertEquals(-20, searchTree1.findMin().get());
193
+    }
194
+
195
+}

Loading…
Cancel
Save