diff --git a/.classpath b/.classpath
index ed0e8f4..e6ce8ae 100644
--- a/.classpath
+++ b/.classpath
@@ -1,42 +1,27 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/org/insa/algo/AbstractAlgorithm.java b/src/main/org/insa/algo/AbstractAlgorithm.java
index bcb0d04..4f664c0 100644
--- a/src/main/org/insa/algo/AbstractAlgorithm.java
+++ b/src/main/org/insa/algo/AbstractAlgorithm.java
@@ -1,24 +1,22 @@
package org.insa.algo ;
+import java.time.Duration;
+import java.time.Instant;
import java.util.ArrayList;
-public abstract class AbstractAlgorithm implements Runnable {
+public abstract class AbstractAlgorithm {
protected AbstractInstance instance;
- protected AbstractSolution solution;
-
- protected ArrayList observers;
+ protected ArrayList observers;
protected AbstractAlgorithm(AbstractInstance instance) {
this.instance = instance;
- this.observers = new ArrayList();
- this.solution = null;
+ this.observers = new ArrayList();
}
- protected AbstractAlgorithm(AbstractInstance instance, ArrayList observers) {
+ protected AbstractAlgorithm(AbstractInstance instance, ArrayList observers) {
this.instance = instance;
this.observers = observers;;
- this.solution = null;
}
/**
@@ -26,44 +24,32 @@ public abstract class AbstractAlgorithm implements Runnable {
*
* @param observer
*/
- public void addObserver(AbstractObserver observer) {
+ public void addObserver(Observer observer) {
observers.add(observer);
}
/**
* @return The list of observers for this algorithm.
*/
- public ArrayList getObservers() {
+ public ArrayList getObservers() {
return observers;
}
- /**
- * Update the current solution.
- *
- * @param solution New solution, or null to unset the current solution.
- *
- */
- protected void updateLastSolution(AbstractSolution solution) {
- this.solution = solution;
- }
-
/**
* @return Instance corresponding to this algorithm.
*/
public AbstractInstance getInstance() { return instance; }
-
- /**
- * @return Last solution, or null if no solution was stored.
- */
- public AbstractSolution getLastSolution() { return solution; }
/**
* Run the algorithm and update the current solution.
*
* @return true if a feasible solution was found (even non-optimal).
*/
- public void run() {
- this.solution = this.doRun();
+ public AbstractSolution run() {
+ Instant start = Instant.now();
+ AbstractSolution solution = this.doRun();
+ solution.setSolvingTime(Duration.between(start, Instant.now()));
+ return solution;
}
/**
diff --git a/src/main/org/insa/algo/AbstractObserver.java b/src/main/org/insa/algo/AbstractObserver.java
deleted file mode 100644
index 53ca878..0000000
--- a/src/main/org/insa/algo/AbstractObserver.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.insa.algo;
-
-public abstract class AbstractObserver {
-
- // Specify if the observer is graphic or not.
- private final boolean isgraphic;
-
- protected AbstractObserver(boolean isGraphic) {
- this.isgraphic = isGraphic;
- }
-
- /**
- * @return true if this observer is graphic (use drawing to display
- * information).
- */
- public boolean isGraphic() {
- return isgraphic;
- }
-
-}
\ No newline at end of file
diff --git a/src/main/org/insa/algo/AbstractSolution.java b/src/main/org/insa/algo/AbstractSolution.java
index 87bddc2..bb23186 100644
--- a/src/main/org/insa/algo/AbstractSolution.java
+++ b/src/main/org/insa/algo/AbstractSolution.java
@@ -35,10 +35,8 @@ public abstract class AbstractSolution {
this.status = Status.UNKNOWN;
}
- protected AbstractSolution(AbstractInstance instance,
- Duration solvingTime, Status status) {
+ protected AbstractSolution(AbstractInstance instance, Status status) {
this.instance = instance;
- this.solvingTime = solvingTime;
this.status = status;
}
@@ -57,6 +55,15 @@ public abstract class AbstractSolution {
*/
public Duration getSolvingTime() { return solvingTime; }
+ /**
+ * Set the solving time of this solution.
+ *
+ * @param solvingTime Solving time for the solution.
+ */
+ protected void setSolvingTime(Duration solvingTime) {
+ this.solvingTime = solvingTime;
+ }
+
/**
* @return true if the solution is feasible or optimal.
*/
diff --git a/src/main/org/insa/algo/strongconnectivity/StronglyConnectedComponentObserver.java b/src/main/org/insa/algo/strongconnectivity/StronglyConnectedComponentObserver.java
new file mode 100644
index 0000000..69f1a01
--- /dev/null
+++ b/src/main/org/insa/algo/strongconnectivity/StronglyConnectedComponentObserver.java
@@ -0,0 +1,30 @@
+package org.insa.algo.strongconnectivity;
+
+import java.util.ArrayList;
+
+import org.insa.graph.Node;
+
+public interface StronglyConnectedComponentObserver {
+
+ /**
+ * Notify that the algorithm is entering a new component.
+ *
+ * @param curNode Starting node for the component.
+ */
+ public void notifyStartComponent(Node curNode);
+
+ /**
+ * Notify that a new node has been found for the current component.
+ *
+ * @param node New node found for the current component.
+ */
+ public void notifyNewNodeInComponent(Node node);
+
+ /**
+ * Notify that the algorithm has computed a new component.
+ *
+ * @param nodes List of nodes in the component.
+ */
+ public void notifyEndComponent(ArrayList nodes);
+
+}
diff --git a/src/main/org/insa/algo/strongconnectivity/StronglyConnectedComponentsAlgorithm.java b/src/main/org/insa/algo/strongconnectivity/StronglyConnectedComponentsAlgorithm.java
index 5973890..183b69f 100644
--- a/src/main/org/insa/algo/strongconnectivity/StronglyConnectedComponentsAlgorithm.java
+++ b/src/main/org/insa/algo/strongconnectivity/StronglyConnectedComponentsAlgorithm.java
@@ -2,7 +2,7 @@ package org.insa.algo.strongconnectivity ;
import org.insa.algo.AbstractAlgorithm;
-public abstract class StronglyConnectedComponentsAlgorithm extends AbstractAlgorithm {
+public abstract class StronglyConnectedComponentsAlgorithm extends AbstractAlgorithm {
/**
*
@@ -12,5 +12,15 @@ public abstract class StronglyConnectedComponentsAlgorithm extends AbstractAlgor
public StronglyConnectedComponentsAlgorithm(StronglyConnectedComponentsInstance instance) {
super(instance);
}
+
+ @Override
+ public StronglyConnectedComponentsSolution run() {
+ return (StronglyConnectedComponentsSolution)super.run();
+ }
+
+ @Override
+ public StronglyConnectedComponentsInstance getInstance() {
+ return (StronglyConnectedComponentsInstance)super.getInstance();
+ }
}
diff --git a/src/main/org/insa/algo/strongconnectivity/StronglyConnectedComponentsSolution.java b/src/main/org/insa/algo/strongconnectivity/StronglyConnectedComponentsSolution.java
index 6018966..3503c72 100644
--- a/src/main/org/insa/algo/strongconnectivity/StronglyConnectedComponentsSolution.java
+++ b/src/main/org/insa/algo/strongconnectivity/StronglyConnectedComponentsSolution.java
@@ -1,6 +1,5 @@
package org.insa.algo.strongconnectivity;
-import java.time.Duration;
import java.util.ArrayList;
import org.insa.algo.AbstractSolution;
@@ -16,8 +15,8 @@ public class StronglyConnectedComponentsSolution extends AbstractSolution {
}
protected StronglyConnectedComponentsSolution(StronglyConnectedComponentsInstance instance,
- Duration solvingTime, Status status, ArrayList> components) {
- super(instance, solvingTime, status);
+ Status status, ArrayList> components) {
+ super(instance, status);
this.components = components;
}
diff --git a/src/main/org/insa/algo/strongconnectivity/TarjanAlgorithm.java b/src/main/org/insa/algo/strongconnectivity/TarjanAlgorithm.java
index a9a9a01..0fe7fac 100644
--- a/src/main/org/insa/algo/strongconnectivity/TarjanAlgorithm.java
+++ b/src/main/org/insa/algo/strongconnectivity/TarjanAlgorithm.java
@@ -1,12 +1,9 @@
package org.insa.algo.strongconnectivity;
-import java.time.Duration;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Stack;
-import org.insa.algo.AbstractSolution;
import org.insa.algo.AbstractSolution.Status;
import org.insa.graph.Arc;
import org.insa.graph.Graph;
@@ -74,7 +71,6 @@ public class TarjanAlgorithm extends StronglyConnectedComponentsAlgorithm {
* @return The strong component containing the given node.
*/
protected void findAndAddStrongComponent(Node v) {
- Graph graph = getInstance().getGraph();
// Update node info, index and push the node.
indexes[v.getId()] = index;
@@ -117,14 +113,11 @@ public class TarjanAlgorithm extends StronglyConnectedComponentsAlgorithm {
}
@Override
- protected AbstractSolution doRun() {
+ protected StronglyConnectedComponentsSolution doRun() {
Graph graph = getInstance().getGraph();
components = new ArrayList>();
- // Starting time...
- Instant start = Instant.now();
-
// Initialize everything
final int nbNodes = graph.getNodes().size();
stack = new Stack();
@@ -144,12 +137,8 @@ public class TarjanAlgorithm extends StronglyConnectedComponentsAlgorithm {
findAndAddStrongComponent(node);
}
}
-
- // Duration...
- Duration solvingTime = Duration.between(start, Instant.now());
- return new StronglyConnectedComponentsSolution((StronglyConnectedComponentsInstance)getInstance(),
- solvingTime, Status.OPTIMAL, components);
+ return new StronglyConnectedComponentsSolution(getInstance(), Status.OPTIMAL, components);
}
}
diff --git a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentGraphicObserver.java b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentGraphicObserver.java
index 09db88a..2f24dd9 100644
--- a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentGraphicObserver.java
+++ b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentGraphicObserver.java
@@ -7,7 +7,7 @@ import org.insa.drawing.Drawing;
import org.insa.drawing.graph.GraphDrawing;
import org.insa.graph.Node;
-public class WeaklyConnectedComponentGraphicObserver extends WeaklyConnectedComponentObserver {
+public class WeaklyConnectedComponentGraphicObserver implements WeaklyConnectedComponentObserver {
private static final Color[] COLORS = {
Color.BLUE, Color.ORANGE, Color.GREEN, Color.YELLOW, Color.RED
@@ -21,7 +21,6 @@ public class WeaklyConnectedComponentGraphicObserver extends WeaklyConnectedComp
private int cindex = 0;
public WeaklyConnectedComponentGraphicObserver(Drawing drawing) {
- super(true);
this.drawing = drawing;
this.gdrawing = new GraphDrawing(drawing);
this.drawing.setAutoRepaint(true);
diff --git a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentObserver.java b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentObserver.java
index 9e6e0a6..9347af6 100644
--- a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentObserver.java
+++ b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentObserver.java
@@ -2,37 +2,29 @@ package org.insa.algo.weakconnectivity;
import java.util.ArrayList;
-import org.insa.algo.AbstractObserver;
import org.insa.graph.Node;
-public abstract class WeaklyConnectedComponentObserver extends AbstractObserver {
+public interface WeaklyConnectedComponentObserver {
- /**
- * {@inheritDoc}
- */
- protected WeaklyConnectedComponentObserver(boolean isGraphic) {
- super(isGraphic);
- }
-
/**
* Notify that the algorithm is entering a new component.
*
* @param curNode Starting node for the component.
*/
- public abstract void notifyStartComponent(Node curNode);
+ public void notifyStartComponent(Node curNode);
/**
* Notify that a new node has been found for the current component.
*
* @param node New node found for the current component.
*/
- public abstract void notifyNewNodeInComponent(Node node);
+ public void notifyNewNodeInComponent(Node node);
/**
* Notify that the algorithm has computed a new component.
*
* @param nodes List of nodes in the component.
*/
- public abstract void notifyEndComponent(ArrayList nodes);
+ public void notifyEndComponent(ArrayList nodes);
}
diff --git a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentTextObserver.java b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentTextObserver.java
index b4d4184..0c4eaf6 100644
--- a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentTextObserver.java
+++ b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentTextObserver.java
@@ -5,7 +5,7 @@ import java.util.ArrayList;
import org.insa.graph.Node;
-public class WeaklyConnectedComponentTextObserver extends WeaklyConnectedComponentObserver {
+public class WeaklyConnectedComponentTextObserver implements WeaklyConnectedComponentObserver {
// Number of the current component.
private int numComponent = 1;
@@ -14,7 +14,6 @@ public class WeaklyConnectedComponentTextObserver extends WeaklyConnectedCompone
PrintStream stream;
public WeaklyConnectedComponentTextObserver(PrintStream stream) {
- super(false);
this.stream = stream;
}
diff --git a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsAlgorithm.java b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsAlgorithm.java
index e9980d7..50adb1b 100644
--- a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsAlgorithm.java
+++ b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsAlgorithm.java
@@ -1,23 +1,18 @@
package org.insa.algo.weakconnectivity;
-import java.time.Duration;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.LinkedList;
import java.util.Queue;
import java.util.HashSet;
import org.insa.algo.AbstractAlgorithm;
-import org.insa.algo.AbstractObserver;
-import org.insa.algo.AbstractSolution;
import org.insa.algo.AbstractSolution.Status;
import org.insa.graph.Arc;
import org.insa.graph.Graph;
import org.insa.graph.Node;
-public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm {
+public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm{
/**
*
@@ -28,6 +23,49 @@ public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm {
super(instance);
}
+ @Override
+ public WeaklyConnectedComponentsSolution run() {
+ return (WeaklyConnectedComponentsSolution)super.run();
+ }
+
+ @Override
+ public WeaklyConnectedComponentsInstance getInstance() {
+ return (WeaklyConnectedComponentsInstance)super.getInstance();
+ }
+
+ /**
+ * Notify all observers that the algorithm is entering a new component.
+ *
+ * @param curNode Starting node for the component.
+ */
+ protected void notifyStartComponent(Node curNode) {
+ for (WeaklyConnectedComponentObserver obs: getObservers()) {
+ obs.notifyStartComponent(curNode);
+ }
+ }
+
+ /**
+ * Notify all observers that a new node has been found for the current component.
+ *
+ * @param node New node found for the current component.
+ */
+ protected void notifyNewNodeInComponent(Node node) {
+ for (WeaklyConnectedComponentObserver obs: getObservers()) {
+ obs.notifyNewNodeInComponent(node);
+ }
+ }
+
+ /**
+ * Notify all observers that the algorithm has computed a new component.
+ *
+ * @param nodes List of nodes in the component.
+ */
+ protected void notifyEndComponent(ArrayList nodes) {
+ for (WeaklyConnectedComponentObserver obs: getObservers()) {
+ obs.notifyEndComponent(nodes);
+ }
+ }
+
/**
* @return An adjacency list for the undirected graph equivalent to the stored graph.
*/
@@ -66,9 +104,8 @@ public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm {
// Using a queue because we are doing a BFS
Queue queue = new LinkedList();
- for (AbstractObserver obs: getObservers()) {
- ((WeaklyConnectedComponentObserver)obs).notifyStartComponent(nodes.get(cur));
- }
+ // Notify observers about the current component.
+ notifyStartComponent(nodes.get(cur));
// Add original node and loop until the queue is empty.
queue.add(cur);
@@ -77,8 +114,8 @@ public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm {
Node node = nodes.get(queue.remove());
component.add(node);
- // notify observers
- for (AbstractObserver obs: getObservers()) ((WeaklyConnectedComponentObserver)obs).notifyNewNodeInComponent(node);
+ // Notify observers
+ notifyNewNodeInComponent(node);
for (Integer destId: ugraph.get(node.getId())) {
Node dest = nodes.get(destId);
@@ -89,18 +126,14 @@ public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm {
}
}
- for (AbstractObserver obs: getObservers()) {
- ((WeaklyConnectedComponentObserver)obs).notifyEndComponent(component);
- }
+ notifyEndComponent(component);
return component;
}
@Override
- protected AbstractSolution doRun() {
+ protected WeaklyConnectedComponentsSolution doRun() {
- Instant start = Instant.now();
-
Graph graph = getInstance().getGraph();
ArrayList> ugraph = createUndirectedGraph();
boolean[] marked = new boolean[graph.getNodes().size()];
@@ -117,11 +150,8 @@ public class WeaklyConnectedComponentsAlgorithm extends AbstractAlgorithm {
// Find next non-marked
for (; cur < marked.length && marked[cur]; ++cur);
}
-
- Duration solvingTime = Duration.between(start, Instant.now());
-
- return new WeaklyConnectedComponentsSolution((WeaklyConnectedComponentsInstance)getInstance(),
- solvingTime, Status.OPTIMAL, components);
+
+ return new WeaklyConnectedComponentsSolution(getInstance(), Status.OPTIMAL, components);
}
}
diff --git a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsSolution.java b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsSolution.java
index a8f82bc..e28e825 100644
--- a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsSolution.java
+++ b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentsSolution.java
@@ -1,6 +1,5 @@
package org.insa.algo.weakconnectivity;
-import java.time.Duration;
import java.util.ArrayList;
import org.insa.algo.AbstractSolution;
@@ -16,8 +15,8 @@ public class WeaklyConnectedComponentsSolution extends AbstractSolution {
}
protected WeaklyConnectedComponentsSolution(WeaklyConnectedComponentsInstance instance,
- Duration solvingTime, Status status, ArrayList> components) {
- super(instance, solvingTime, status);
+ Status status, ArrayList> components) {
+ super(instance, status);
this.components = components;
}
diff --git a/src/main/org/insa/base/MainWindow.java b/src/main/org/insa/base/MainWindow.java
index d2e1399..f296fde 100644
--- a/src/main/org/insa/base/MainWindow.java
+++ b/src/main/org/insa/base/MainWindow.java
@@ -5,17 +5,23 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
-import java.lang.reflect.Constructor;
+import java.time.Duration;
+import java.time.Instant;
import java.util.ArrayList;
import javax.swing.BorderFactory;
-import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
@@ -30,10 +36,10 @@ import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
+import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.filechooser.FileNameExtensionFilter;
-import org.insa.algo.AbstractSolution;
import org.insa.algo.shortestpath.BellmanFordAlgorithm;
import org.insa.algo.shortestpath.ShortestPathAlgorithm;
import org.insa.algo.shortestpath.ShortestPathGraphicObserver;
@@ -41,7 +47,6 @@ import org.insa.algo.shortestpath.ShortestPathInstance;
import org.insa.algo.shortestpath.ShortestPathInstance.Mode;
import org.insa.algo.shortestpath.ShortestPathSolution;
import org.insa.algo.weakconnectivity.WeaklyConnectedComponentGraphicObserver;
-import org.insa.algo.weakconnectivity.WeaklyConnectedComponentTextObserver;
import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsAlgorithm;
import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsInstance;
import org.insa.drawing.Drawing;
@@ -49,17 +54,17 @@ import org.insa.drawing.graph.BlackAndWhiteGraphPalette;
import org.insa.drawing.graph.GraphDrawing;
import org.insa.drawing.graph.PathDrawing;
import org.insa.graph.Graph;
+import org.insa.graph.Node;
import org.insa.graph.Path;
+import org.insa.graph.Point;
import org.insa.graph.io.BinaryGraphReader;
import org.insa.graph.io.BinaryPathReader;
import org.insa.graph.io.MapMismatchException;
import org.insa.graph.io.Openfile;
-import com.sun.glass.events.KeyEvent;
-
public class MainWindow extends JFrame {
- public class JOutputStream extends OutputStream {
+ protected class JOutputStream extends OutputStream {
private JTextArea textArea;
public JOutputStream(JTextArea textArea) {
@@ -76,7 +81,91 @@ public class MainWindow extends JFrame {
textArea.update(textArea.getGraphics());
}
}
+
+ protected interface CallableWithNodes {
+
+ void call(ArrayList nodes);
+
+ };
+ protected class DrawingClickListener extends MouseAdapter {
+
+ // Enable/Disable.
+ private boolean enabled = false;
+
+ // List of points.
+ private ArrayList points = new ArrayList();
+
+ // Number of points to find before running.
+ private int nTargetPoints = 0;
+
+ // Callable to call when points are reached.
+ CallableWithNodes callable = null;
+
+ /**
+ * @return true if this listener is enabled.
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * Enable this listener.
+ *
+ * @param nTargetPoints Number of point to found before calling the callable.
+ */
+ public void enable(int nTargetPoints, CallableWithNodes callable) {
+ this.enabled = true;
+ MainWindow.this.getJMenuBar().setEnabled(false);
+ this.nTargetPoints = nTargetPoints;
+ this.points.clear();
+ this.callable = callable;
+ }
+
+ /**
+ * Disable this listener.
+ */
+ public void disable() {
+ this.enabled = false;
+ MainWindow.this.getJMenuBar().setEnabled(true);
+ }
+
+ public void mouseClicked(MouseEvent evt) {
+ if (!isEnabled()) {
+ return;
+ }
+ Point lonlat;
+ try {
+ lonlat = drawing.getLongitudeLatitude(evt);
+ }
+ catch (NoninvertibleTransformException e) {
+ // Should never happens in "normal" circumstances...
+ e.printStackTrace();
+ return;
+ }
+
+ System.out.println("MOUSE CLICKED: " + evt.getPoint() + " -> " + lonlat);
+
+ ArrayList nodes = graph.getNodes();
+ Node node = null;
+ double minDis = Double.POSITIVE_INFINITY;
+ for (int n = 0 ; n < nodes.size(); ++n) {
+ double dis = lonlat.distanceTo(nodes.get(n).getPoint());
+ if (dis < minDis) {
+ node = nodes.get(n);
+ minDis = dis;
+ }
+ }
+ new GraphDrawing(drawing).drawPoint(node.getPoint(), 10, Color.BLUE);
+ points.add(node);
+ if (points.size() == nTargetPoints) {
+ System.out.println("CALLABLE!");
+ callable.call(points);
+ this.disable();
+ }
+ }
+ };
+
/**
*
*/
@@ -86,11 +175,11 @@ public class MainWindow extends JFrame {
*
*/
private static final String WINDOW_TITLE = "BE Graphes INSA";
-
+
/**
*
*/
- private static final Dimension DEFAULT_DIMENSION = new Dimension(800, 600);
+ private static final int THREAD_TIMER_DELAY = 1000; // in milliseconds
// Current graph.
private Graph graph;
@@ -98,6 +187,10 @@ public class MainWindow extends JFrame {
// Current loaded path.
private Path currentPath;
+ // Drawing and click adapter.
+ private Drawing drawing;
+ private DrawingClickListener clickAdapter;
+
// List of item for the top menus.
private JMenuItem openMapItem;
@@ -107,25 +200,24 @@ public class MainWindow extends JFrame {
// Label containing the map ID of the current graph.
private JLabel mapIdPanel;
+ // Thread information
+ private Instant threadStartTime;
+ private Timer threadTimer;
private JPanel threadPanel;
// Log stream and print stream
private JOutputStream logStream;
+
+ @SuppressWarnings("unused")
private PrintStream printStream;
// Current running thread
private Thread currentThread;
- /**
- *
- */
- private Drawing drawing;
-
public MainWindow() {
super(WINDOW_TITLE);
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setLayout(new BorderLayout());
- setSize(DEFAULT_DIMENSION);
setJMenuBar(createMenuBar());
addWindowListener(new WindowAdapter() {
@@ -145,7 +237,10 @@ public class MainWindow extends JFrame {
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
drawing = new Drawing();
- drawing.setBackground(Color.WHITE);
+
+ // Click adapter
+ this.clickAdapter = new DrawingClickListener();
+ drawing.addMouseListener(this.clickAdapter);
JTextArea infoPanel = new JTextArea();
infoPanel.setMinimumSize(new Dimension(200, 50));
@@ -168,22 +263,45 @@ public class MainWindow extends JFrame {
this.add(createStatusBar(), BorderLayout.SOUTH);
}
- private void launchThread(Runnable runnable) {
- currentThread = new Thread(new Runnable() {
- @Override
- public void run() {
- threadPanel.setVisible(true);
- runnable.run();
- threadPanel.setVisible(false);
- }
- });
+ private void restartThreadTimer() {
+ threadStartTime = Instant.now();
+ threadTimer.restart();
+ }
+
+ private void stopThreadTimer() {
+ threadTimer.stop();
+ }
+
+ /**
+ * @param runnable
+ * @param canInterrupt
+ */
+ private void launchThread(Runnable runnable, boolean canInterrupt) {
+ if (canInterrupt) {
+ currentThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ restartThreadTimer();
+ threadPanel.setVisible(true);
+ runnable.run();
+ clearCurrentThread();
+ }
+ });
+ }
+ else {
+ currentThread = new Thread(runnable);
+ }
currentThread.start();
}
-
- private ShortestPathInstance getShortestPathParameters() {
- // TODO: Select origin / end nodes.
- return new ShortestPathInstance(
- graph, graph.getNodes().get(2), graph.getNodes().get(139), Mode.TIME);
+ private void launchThread(Runnable runnable) {
+ launchThread(runnable, true);
+ }
+
+
+ private void clearCurrentThread() {
+ stopThreadTimer();
+ threadPanel.setVisible(false);
+ currentThread = null;
}
private void launchShortestPathThread(ShortestPathAlgorithm spAlgorithm) {
@@ -192,16 +310,14 @@ public class MainWindow extends JFrame {
launchThread(new Runnable() {
@Override
public void run() {
- spAlgorithm.run();
- AbstractSolution solution = spAlgorithm.getLastSolution();
+ ShortestPathSolution solution = spAlgorithm.run();
if (solution != null && solution.isFeasible()) {
- new PathDrawing(drawing).drawPath(((ShortestPathSolution)solution).getPath());
+ new PathDrawing(drawing).drawPath(solution.getPath());
}
}
});
}
- @SuppressWarnings("restriction")
private JMenuBar createMenuBar() {
// Open Map item...
@@ -218,28 +334,33 @@ public class MainWindow extends JFrame {
chooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
chooser.setFileFilter(filter);
if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) {
- BinaryGraphReader reader;
- try {
- reader = new BinaryGraphReader(
- Openfile.open(chooser.getSelectedFile().getAbsolutePath()));
- } catch (IOException e1) {
- JOptionPane.showMessageDialog(MainWindow.this, "Cannot open the selected file.");
- return ;
- }
- try {
- graph = reader.read();
- }
- catch (Exception exception) {
- JOptionPane.showMessageDialog(MainWindow.this, "Unable to read graph from the selected file.");
- return ;
- }
- drawing.clear();
- new GraphDrawing(drawing).drawGraph(graph);
+ launchThread(new Runnable() {
+ @Override
+ public void run() {
+ BinaryGraphReader reader;
+ try {
+ reader = new BinaryGraphReader(
+ Openfile.open(chooser.getSelectedFile().getAbsolutePath()));
+ } catch (IOException e1) {
+ JOptionPane.showMessageDialog(MainWindow.this, "Cannot open the selected file.");
+ return ;
+ }
+ try {
+ graph = reader.read();
+ }
+ catch (Exception exception) {
+ JOptionPane.showMessageDialog(MainWindow.this, "Unable to read graph from the selected file.");
+ return ;
+ }
+ drawing.clear();
+ new GraphDrawing(drawing).drawGraph(graph);
- for (JMenuItem item: graphItems) {
- item.setEnabled(true);
- }
- mapIdPanel.setText("Map ID: 0x" + Integer.toHexString(graph.getMapId()));
+ for (JMenuItem item: graphItems) {
+ item.setEnabled(true);
+ }
+ mapIdPanel.setText("Map ID: 0x" + Integer.toHexString(graph.getMapId()));
+ }
+ }, false);
}
}
});
@@ -352,7 +473,12 @@ public class MainWindow extends JFrame {
WeaklyConnectedComponentsAlgorithm algo = new WeaklyConnectedComponentsAlgorithm(instance);
algo.addObserver(new WeaklyConnectedComponentGraphicObserver(drawing));
// algo.addObserver(new WeaklyConnectedComponentTextObserver(printStream));
- launchThread(algo);
+ launchThread(new Runnable() {
+ @Override
+ public void run() {
+ algo.run();
+ }
+ });
}
});
@@ -361,7 +487,13 @@ public class MainWindow extends JFrame {
bellmanItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- launchShortestPathThread(new BellmanFordAlgorithm(getShortestPathParameters()));
+ clickAdapter.enable(2, new CallableWithNodes() {
+ @Override
+ public void call(ArrayList nodes) {
+ launchShortestPathThread(new BellmanFordAlgorithm(
+ new ShortestPathInstance(graph, nodes.get(0), nodes.get(1), Mode.TIME)));
+ }
+ });
}
});
graphItems.add(wccItem);
@@ -386,12 +518,20 @@ public class MainWindow extends JFrame {
return menuBar;
}
+
+ @SuppressWarnings("deprecation")
+ private void stopCurrentThread() {
+ // Should not be used in production code, but here I have no idea how
+ // to do this properly... Cannot use .interrupt() because it would requires
+ // the algorithm to watch the ThreadInteruption exception.
+ currentThread.stop();
+ }
private JPanel createStatusBar() {
// create the status bar panel and shove it down the bottom of the frame
JPanel statusPanel = new JPanel();
statusPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY));
- statusPanel.setPreferredSize(new Dimension(getWidth(), 34));
+ statusPanel.setPreferredSize(new Dimension(getWidth(), 38));
statusPanel.setLayout(new BorderLayout());
mapIdPanel = new JLabel();
@@ -399,9 +539,10 @@ public class MainWindow extends JFrame {
statusPanel.add(mapIdPanel, BorderLayout.WEST);
JLabel threadInfo = new JLabel("Thread running... ");
+ JLabel threadTimerLabel = new JLabel("00:00:00");
JButton threadButton = new JButton("Stop");
threadButton.addActionListener(new ActionListener() {
- @SuppressWarnings("deprecation")
+
@Override
public void actionPerformed(ActionEvent e) {
if (currentThread != null && currentThread.isAlive()) {
@@ -409,17 +550,30 @@ public class MainWindow extends JFrame {
"Are you sure you want to kill the running thread?", "Kill Confirmation",
JOptionPane.YES_NO_OPTION);
if (confirmed == JOptionPane.YES_OPTION) {
- currentThread.stop();
- currentThread = null;
+ stopCurrentThread();
+ clearCurrentThread();
threadPanel.setVisible(false);
}
}
}
});
+
+ threadTimer = new Timer(THREAD_TIMER_DELAY, new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Duration elapsed = Duration.between(threadStartTime, Instant.now());
+ long seconds = elapsed.getSeconds();
+ threadTimerLabel.setText(String.format(
+ "%02d:%02d:%02d", seconds/3600, seconds/60 % 60, seconds % 60));
+ }
+ });
+ threadTimer.setInitialDelay(0);
+
threadPanel = new JPanel();
threadPanel.add(threadInfo);
+ threadPanel.add(threadTimerLabel);
threadPanel.add(threadButton);
- // threadPanel.setVisible(false);
+ threadPanel.setVisible(false);
statusPanel.add(threadPanel, BorderLayout.EAST);
return statusPanel;
diff --git a/src/main/org/insa/drawing/Drawing.java b/src/main/org/insa/drawing/Drawing.java
index f19cbd2..ce6c8c9 100644
--- a/src/main/org/insa/drawing/Drawing.java
+++ b/src/main/org/insa/drawing/Drawing.java
@@ -5,10 +5,15 @@ import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
+import java.awt.event.MouseEvent;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Point2D;
import java.awt.image.*;
import javax.swing.JPanel;
+import org.insa.graph.Point;
+
/**
* Cette implementation de la classe Dessin produit vraiment un affichage
* (au contraire de la classe DessinInvisible).
@@ -23,15 +28,10 @@ public class Drawing extends JPanel {
private final Graphics2D gr;
- private float long1;
- private float long2;
- private float lat1;
- private float lat2;
+ private double long1, long2, lat1, lat2;
// Width and height of the image
private final int width, height;
-
- private boolean bb_is_set ;
private Image image;
private ZoomAndPanListener zoomAndPanListener;
@@ -57,14 +57,11 @@ public class Drawing extends JPanel {
this.gr = img.createGraphics();
this.zoomAndPanListener.setCoordTransform(this.gr.getTransform());
-
- this.bb_is_set = false;
-
- this.long1 = 0.0f;
- this.long2 = this.width;
- this.lat1 = 0.0f;
- this.lat2 = this.height;
+ this.long1 = -180;
+ this.long2 = 180;
+ this.lat1 = -90;
+ this.lat2 = 90;
this.clear();
this.repaint();
@@ -108,13 +105,11 @@ public class Drawing extends JPanel {
throw new Error("DessinVisible.setBB : mauvaises coordonnees.");
}
- this.long1 = (float)long1;
- this.long2 = (float)long2;
- this.lat1= (float)lat1;
- this.lat2 = (float)lat2;
-
- this.bb_is_set = true;
-
+ this.long1 = long1;
+ this.long2 = long2;
+ this.lat1= lat1;
+ this.lat2 = lat2;
+
double scale = 1 / Math.max(this.width / (double)this.getWidth(), this.height / (double)this.getHeight());
this.zoomAndPanListener.getCoordTransform().setToIdentity();
@@ -126,44 +121,58 @@ public class Drawing extends JPanel {
}
- private int projx(float lon) {
+ private int projx(double lon) {
return (int)(width * (lon - this.long1) / (this.long2 - this.long1)) ;
}
- private int projy(float lat) {
+ private int projy(double lat) {
return (int)(height * (1 - (lat - this.lat1) / (this.lat2 - this.lat1))) ;
}
-
- private void checkBB() {
- if (!this.bb_is_set) {
- throw new Error("Classe DessinVisible : vous devez invoquer la methode setBB avant de dessiner.") ;
- }
+
+ /**
+ * Return the longitude and latitude corresponding to the given
+ * position of the MouseEvent.
+ *
+ * @param event
+ *
+ * @return
+ */
+ public Point getLongitudeLatitude(MouseEvent event) throws NoninvertibleTransformException {
+ // Get the point using the inverse transform of the Zoom/Pan object, this gives us
+ // a point within the drawing box (between [0, 0] and [width, height]).
+ Point2D ptDst = this.zoomAndPanListener.getCoordTransform().inverseTransform(event.getPoint(), null);
+
+ // Inverse the "projection" on x/y to get longitude and latitude.
+ double lon = ptDst.getX();
+ double lat = ptDst.getY();
+ lon = (lon / this.width) * (this.long2 - this.long1) + this.long1;
+ lat = (1 - lat / this.height) * (this.lat2 - this.lat1) + this.lat1;
+
+ // Return a new point.
+ return new Point(lon, lat);
}
- public void drawLine(float long1, float lat1, float long2, float lat2) {
- this.checkBB() ;
- int x1 = this.projx(long1) ;
- int x2 = this.projx(long2) ;
- int y1 = this.projy(lat1) ;
- int y2 = this.projy(lat2) ;
+ public void drawLine(Point from, Point to) {
+ int x1 = this.projx(from.getLongitude()) ;
+ int x2 = this.projx(to.getLongitude()) ;
+ int y1 = this.projy(from.getLatitude()) ;
+ int y2 = this.projy(to.getLatitude()) ;
gr.drawLine(x1, y1, x2, y2) ;
this.doAutoPaint();
}
- public void drawPoint(float lon, float lat, int width) {
- this.checkBB() ;
- int x = this.projx(lon) - width / 2 ;
- int y = this.projy(lat) - width / 2 ;
- gr.fillOval (x, y, width, width) ;
+ public void drawPoint(Point point, int width) {
+ int x = this.projx(point.getLongitude()) - width / 2;
+ int y = this.projy(point.getLatitude()) - width / 2;
+ gr.fillOval(x, y, width, width);
this.doAutoPaint();
}
- public void putText(float lon, float lat, String txt) {
- this.checkBB() ;
- int x = this.projx(lon) ;
- int y = this.projy(lat) ;
- gr.drawString (txt, x, y) ;
+ public void putText(Point point, String txt) {
+ int x = this.projx(point.getLongitude());
+ int y = this.projy(point.getLatitude());
+ gr.drawString(txt, x, y);
this.doAutoPaint();
}
diff --git a/src/main/org/insa/drawing/graph/GraphDrawing.java b/src/main/org/insa/drawing/graph/GraphDrawing.java
index 5bb0ea7..e64a001 100644
--- a/src/main/org/insa/drawing/graph/GraphDrawing.java
+++ b/src/main/org/insa/drawing/graph/GraphDrawing.java
@@ -9,7 +9,6 @@ import org.insa.graph.Arc;
import org.insa.graph.Graph;
import org.insa.graph.Node;
import org.insa.graph.Point;
-import org.insa.graph.RoadInformation.RoadType;
public class GraphDrawing {
@@ -30,8 +29,7 @@ public class GraphDrawing {
}
public void drawLine(Point p1, Point p2) {
- drawing.drawLine(p1.getLongitude(), p1.getLatitude(),
- p2.getLongitude(), p2.getLatitude());
+ drawing.drawLine(p1, p2);
}
public void drawPoint(Point p) {
@@ -39,12 +37,12 @@ public class GraphDrawing {
}
public void drawPoint(Point p, int width) {
- drawing.drawPoint(p.getLongitude(), p.getLatitude(), width);
+ drawing.drawPoint(p, width);
}
public void drawPoint(Point p, int width, Color c) {
drawing.setColor(c);
- drawing.drawPoint(p.getLongitude(), p.getLatitude(), width);
+ drawing.drawPoint(p, width);
}
/**
diff --git a/src/main/org/insa/graph/Point.java b/src/main/org/insa/graph/Point.java
index 162c147..8aa353f 100644
--- a/src/main/org/insa/graph/Point.java
+++ b/src/main/org/insa/graph/Point.java
@@ -26,14 +26,14 @@ public class Point {
}
// Longitude and latitude of the point.
- private float longitude, latitude;
+ private double longitude, latitude;
/**
*
* @param longitude Longitude of the point, in degrees.
* @param latitude Latitude of the point, in degrees.
*/
- public Point(float longitude, float latitude) {
+ public Point(double longitude, double latitude) {
this.longitude = longitude;
this.latitude = latitude;
}
@@ -41,12 +41,12 @@ public class Point {
/**
* @return Longitude of this point (in degrees).
*/
- public float getLongitude() { return longitude; }
+ public double getLongitude() { return longitude; }
/**
* @return Latitude of this point (in degrees).
*/
- public float getLatitude() { return latitude; }
+ public double getLatitude() { return latitude; }
/**
* Compute the distance from this point to the given point
@@ -58,5 +58,9 @@ public class Point {
public double distanceTo(Point target) {
return distance(this, target);
}
-
+
+ @Override
+ public String toString() {
+ return String.format("Point(%f, %f)", getLongitude(), getLatitude());
+ }
}
diff --git a/src/main/org/insa/graph/io/BinaryPathReader.java b/src/main/org/insa/graph/io/BinaryPathReader.java
index 0819a51..6746014 100644
--- a/src/main/org/insa/graph/io/BinaryPathReader.java
+++ b/src/main/org/insa/graph/io/BinaryPathReader.java
@@ -65,7 +65,7 @@ public class BinaryPathReader extends BinaryReader implements AbstractPathReader
current = node;
}
- return new Path(graph, nodes.get(0), arcs);
+ return new Path(graph, arcs);
}
/**