Make solution panel a bit more generic using reflections.
This commit is contained in:
parent
6d8c2462ab
commit
f22c1c93fa
5 changed files with 209 additions and 134 deletions
|
@ -1,22 +1,100 @@
|
||||||
package org.insa.algo;
|
package org.insa.algo;
|
||||||
|
|
||||||
|
import org.insa.graph.Arc;
|
||||||
import org.insa.graph.Graph;
|
import org.insa.graph.Graph;
|
||||||
|
|
||||||
public abstract class AbstractInputData {
|
public abstract class AbstractInputData {
|
||||||
|
|
||||||
protected Graph graph;
|
public enum Mode {
|
||||||
|
TIME, LENGTH
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new AbstractInputData instance with the given graph.
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ArcFilter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param arc
|
||||||
|
*
|
||||||
|
* @return true if the given arc is allowed.
|
||||||
|
*/
|
||||||
|
public boolean isAllowed(Arc arc);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Graph
|
||||||
|
protected Graph graph;
|
||||||
|
|
||||||
|
// Mode for the computation of the costs.
|
||||||
|
private final AbstractInputData.Mode mode;
|
||||||
|
|
||||||
|
// Arc filter.
|
||||||
|
private final AbstractInputData.ArcFilter arcFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new AbstractInputData instance for the given graph, mode and filter.
|
||||||
*
|
*
|
||||||
* @param graph
|
* @param graph
|
||||||
*/
|
*/
|
||||||
protected AbstractInputData(Graph graph) {
|
protected AbstractInputData(Graph graph, Mode mode, ArcFilter arcFilter) {
|
||||||
this.graph = graph;
|
this.graph = graph;
|
||||||
|
this.mode = mode;
|
||||||
|
this.arcFilter = arcFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new AbstractInputData instance for the given graph and mode, with no
|
||||||
|
* filtering on the arc.
|
||||||
|
*
|
||||||
|
* @param graph
|
||||||
|
* @param mode
|
||||||
|
*/
|
||||||
|
protected AbstractInputData(Graph graph, Mode mode) {
|
||||||
|
this(graph, mode, new AbstractInputData.ArcFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean isAllowed(Arc arc) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new AbstractInputData instance for the given graph, with default
|
||||||
|
* mode (LENGHT), with no filtering on the arc.
|
||||||
|
*
|
||||||
|
* @param graph
|
||||||
|
* @param mode
|
||||||
|
*/
|
||||||
|
protected AbstractInputData(Graph graph) {
|
||||||
|
this(graph, Mode.LENGTH, new AbstractInputData.ArcFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean isAllowed(Arc arc) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Graph associated with this input.
|
||||||
|
*/
|
||||||
public Graph getGraph() {
|
public Graph getGraph() {
|
||||||
return graph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Mode of the algorithm (time or length).
|
||||||
|
*/
|
||||||
|
public Mode getMode() {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the given arc is allowed.
|
||||||
|
*/
|
||||||
|
public boolean isAllowed(Arc arc) {
|
||||||
|
return this.arcFilter.isAllowed(arc);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,12 @@ import org.insa.graph.Graph;
|
||||||
|
|
||||||
public class StronglyConnectedComponentsData extends AbstractInputData {
|
public class StronglyConnectedComponentsData extends AbstractInputData {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param graph
|
* @param graph
|
||||||
*/
|
*/
|
||||||
public StronglyConnectedComponentsData(Graph graph) {
|
public StronglyConnectedComponentsData(Graph graph) {
|
||||||
super(graph);
|
super(graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,16 +25,16 @@ import javax.swing.JRadioButton;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
|
|
||||||
import org.insa.algo.AbstractAlgorithm;
|
import org.insa.algo.AbstractAlgorithm;
|
||||||
|
import org.insa.algo.AbstractInputData;
|
||||||
|
import org.insa.algo.AbstractInputData.ArcFilter;
|
||||||
|
import org.insa.algo.AbstractInputData.Mode;
|
||||||
import org.insa.algo.AlgorithmFactory;
|
import org.insa.algo.AlgorithmFactory;
|
||||||
import org.insa.algo.shortestpath.ShortestPathAlgorithm;
|
|
||||||
import org.insa.algo.shortestpath.ShortestPathData.ArcFilter;
|
|
||||||
import org.insa.algo.shortestpath.ShortestPathData.Mode;
|
|
||||||
import org.insa.graph.Arc;
|
import org.insa.graph.Arc;
|
||||||
import org.insa.graph.Node;
|
import org.insa.graph.Node;
|
||||||
import org.insa.graph.RoadInformation.AccessMode;
|
import org.insa.graph.RoadInformation.AccessMode;
|
||||||
import org.insa.graphics.NodesInputPanel.InputChangedEvent;
|
import org.insa.graphics.NodesInputPanel.InputChangedEvent;
|
||||||
|
|
||||||
public class ShortestPathPanel extends JPanel {
|
public class AlgorithmPanel extends JPanel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -53,17 +53,17 @@ public class ShortestPathPanel extends JPanel {
|
||||||
protected static final int START_EVENT_ID = 0x1;
|
protected static final int START_EVENT_ID = 0x1;
|
||||||
|
|
||||||
private final List<Node> nodes;
|
private final List<Node> nodes;
|
||||||
private final Mode mode;
|
private final AbstractInputData.Mode mode;
|
||||||
private final Class<? extends AbstractAlgorithm<?>> algoClass;
|
private final Class<? extends AbstractAlgorithm<?>> algoClass;
|
||||||
|
|
||||||
private final ArcFilter arcFilter;
|
private final AbstractInputData.ArcFilter arcFilter;
|
||||||
|
|
||||||
private final boolean graphicVisualization;
|
private final boolean graphicVisualization;
|
||||||
private final boolean textualVisualization;
|
private final boolean textualVisualization;
|
||||||
|
|
||||||
public StartActionEvent(Class<? extends AbstractAlgorithm<?>> algoClass, List<Node> nodes, Mode mode,
|
public StartActionEvent(Class<? extends AbstractAlgorithm<?>> algoClass, List<Node> nodes, AbstractInputData.Mode mode,
|
||||||
ArcFilter arcFilter, boolean graphicVisualization, boolean textualVisualization) {
|
AbstractInputData.ArcFilter arcFilter, boolean graphicVisualization, boolean textualVisualization) {
|
||||||
super(ShortestPathPanel.this, START_EVENT_ID, START_EVENT_COMMAND);
|
super(AlgorithmPanel.this, START_EVENT_ID, START_EVENT_COMMAND);
|
||||||
this.nodes = nodes;
|
this.nodes = nodes;
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
this.algoClass = algoClass;
|
this.algoClass = algoClass;
|
||||||
|
@ -82,14 +82,14 @@ public class ShortestPathPanel extends JPanel {
|
||||||
/**
|
/**
|
||||||
* @return Mode associated with this event.
|
* @return Mode associated with this event.
|
||||||
*/
|
*/
|
||||||
public Mode getMode() {
|
public AbstractInputData.Mode getMode() {
|
||||||
return this.mode;
|
return this.mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Arc filter associated with this event.
|
* @return Arc filter associated with this event.
|
||||||
*/
|
*/
|
||||||
public ArcFilter getArcFilter() {
|
public AbstractInputData.ArcFilter getArcFilter() {
|
||||||
return this.arcFilter;
|
return this.arcFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ public class ShortestPathPanel extends JPanel {
|
||||||
protected NodesInputPanel nodesInputPanel;
|
protected NodesInputPanel nodesInputPanel;
|
||||||
|
|
||||||
// Solution
|
// Solution
|
||||||
protected ShortestPathSolutionPanel solutionPanel;
|
protected SolutionPanel solutionPanel;
|
||||||
|
|
||||||
// Component that can be enabled/disabled.
|
// Component that can be enabled/disabled.
|
||||||
private ArrayList<JComponent> components = new ArrayList<>();
|
private ArrayList<JComponent> components = new ArrayList<>();
|
||||||
|
@ -132,7 +132,7 @@ public class ShortestPathPanel extends JPanel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
public ShortestPathPanel(Component parent) {
|
public AlgorithmPanel(Component parent, Class<? extends AbstractAlgorithm<?>> baseAlgorithm) {
|
||||||
super();
|
super();
|
||||||
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ public class ShortestPathPanel extends JPanel {
|
||||||
|
|
||||||
// Add algorithm selection
|
// Add algorithm selection
|
||||||
JComboBox<String> algoSelect = new JComboBox<>(
|
JComboBox<String> algoSelect = new JComboBox<>(
|
||||||
AlgorithmFactory.getAlgorithmNames(ShortestPathAlgorithm.class).toArray(new String[0]));
|
AlgorithmFactory.getAlgorithmNames(baseAlgorithm).toArray(new String[0]));
|
||||||
algoSelect.setBackground(Color.WHITE);
|
algoSelect.setBackground(Color.WHITE);
|
||||||
algoSelect.setAlignmentX(Component.LEFT_ALIGNMENT);
|
algoSelect.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
add(algoSelect);
|
add(algoSelect);
|
||||||
|
@ -168,7 +168,7 @@ public class ShortestPathPanel extends JPanel {
|
||||||
add(this.nodesInputPanel);
|
add(this.nodesInputPanel);
|
||||||
components.add(this.nodesInputPanel);
|
components.add(this.nodesInputPanel);
|
||||||
|
|
||||||
JComboBox<ArcFilter> arcFilterSelect = new JComboBox<>(new ArcFilter[] { new ArcFilter() {
|
JComboBox<AbstractInputData.ArcFilter> arcFilterSelect = new JComboBox<>(new AbstractInputData.ArcFilter[] { new AbstractInputData.ArcFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean isAllowed(Arc arc) {
|
public boolean isAllowed(Arc arc) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -178,7 +178,7 @@ public class ShortestPathPanel extends JPanel {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "All arcs are allowed";
|
return "All arcs are allowed";
|
||||||
}
|
}
|
||||||
}, new ArcFilter() {
|
}, new AbstractInputData.ArcFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean isAllowed(Arc arc) {
|
public boolean isAllowed(Arc arc) {
|
||||||
return arc.getRoadInformation().getAccessRestrictions().isAllowedFor(AccessMode.MOTORCAR)
|
return arc.getRoadInformation().getAccessRestrictions().isAllowedFor(AccessMode.MOTORCAR)
|
||||||
|
@ -250,7 +250,7 @@ public class ShortestPathPanel extends JPanel {
|
||||||
|
|
||||||
add(modeAndObserverPanel);
|
add(modeAndObserverPanel);
|
||||||
|
|
||||||
solutionPanel = new ShortestPathSolutionPanel(parent);
|
solutionPanel = new SolutionPanel(parent);
|
||||||
solutionPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
solutionPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
solutionPanel.setVisible(false);
|
solutionPanel.setVisible(false);
|
||||||
add(Box.createVerticalStrut(10));
|
add(Box.createVerticalStrut(10));
|
||||||
|
@ -265,13 +265,12 @@ public class ShortestPathPanel extends JPanel {
|
||||||
startAlgoButton.addActionListener(new ActionListener() {
|
startAlgoButton.addActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
Mode mode = lengthModeButton.isSelected() ? Mode.LENGTH : Mode.TIME;
|
AbstractInputData.Mode mode = lengthModeButton.isSelected() ? AbstractInputData.Mode.LENGTH : AbstractInputData.Mode.TIME;
|
||||||
|
|
||||||
for (ActionListener lis: startActionListeners) {
|
for (ActionListener lis: startActionListeners) {
|
||||||
lis.actionPerformed(new StartActionEvent(
|
lis.actionPerformed(new StartActionEvent(
|
||||||
AlgorithmFactory.getAlgorithmClass(ShortestPathAlgorithm.class,
|
AlgorithmFactory.getAlgorithmClass(baseAlgorithm, (String) algoSelect.getSelectedItem()),
|
||||||
(String) algoSelect.getSelectedItem()),
|
nodesInputPanel.getNodeForInputs(), mode, (AbstractInputData.ArcFilter) arcFilterSelect.getSelectedItem(),
|
||||||
nodesInputPanel.getNodeForInputs(), mode, (ArcFilter) arcFilterSelect.getSelectedItem(),
|
|
||||||
graphicObserver.isSelected(), textObserver.isSelected()));
|
graphicObserver.isSelected(), textObserver.isSelected()));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -58,7 +58,7 @@ import org.insa.graph.io.BinaryGraphReaderInsa2018;
|
||||||
import org.insa.graph.io.BinaryPathReader;
|
import org.insa.graph.io.BinaryPathReader;
|
||||||
import org.insa.graph.io.GraphReader;
|
import org.insa.graph.io.GraphReader;
|
||||||
import org.insa.graph.io.MapMismatchException;
|
import org.insa.graph.io.MapMismatchException;
|
||||||
import org.insa.graphics.ShortestPathPanel.StartActionEvent;
|
import org.insa.graphics.AlgorithmPanel.StartActionEvent;
|
||||||
import org.insa.graphics.drawing.BasicGraphPalette;
|
import org.insa.graphics.drawing.BasicGraphPalette;
|
||||||
import org.insa.graphics.drawing.BlackAndWhiteGraphPalette;
|
import org.insa.graphics.drawing.BlackAndWhiteGraphPalette;
|
||||||
import org.insa.graphics.drawing.Drawing;
|
import org.insa.graphics.drawing.Drawing;
|
||||||
|
@ -107,7 +107,7 @@ public class MainWindow extends JFrame {
|
||||||
private JSplitPane mainPanel;
|
private JSplitPane mainPanel;
|
||||||
|
|
||||||
// Shortest path panel
|
// Shortest path panel
|
||||||
private ShortestPathPanel spPanel;
|
private AlgorithmPanel spPanel;
|
||||||
|
|
||||||
// List of items that cannot be used without a graph
|
// List of items that cannot be used without a graph
|
||||||
private ArrayList<JMenuItem> graphLockItems = new ArrayList<JMenuItem>();
|
private ArrayList<JMenuItem> graphLockItems = new ArrayList<JMenuItem>();
|
||||||
|
@ -148,7 +148,7 @@ public class MainWindow extends JFrame {
|
||||||
|
|
||||||
this.drawing = this.basicDrawing;
|
this.drawing = this.basicDrawing;
|
||||||
|
|
||||||
spPanel = new ShortestPathPanel(this);
|
spPanel = new AlgorithmPanel(this, ShortestPathAlgorithm.class);
|
||||||
spPanel.addStartActionListener(new ActionListener() {
|
spPanel.addStartActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
|
|
@ -4,48 +4,45 @@ import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.io.BufferedOutputStream;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.io.DataOutputStream;
|
import java.lang.reflect.Method;
|
||||||
import java.io.File;
|
import java.util.ArrayList;
|
||||||
import java.io.FileOutputStream;
|
import java.util.List;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.Box;
|
import javax.swing.Box;
|
||||||
import javax.swing.BoxLayout;
|
import javax.swing.BoxLayout;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
import javax.swing.JFileChooser;
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JTextArea;
|
import javax.swing.JTextArea;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.border.CompoundBorder;
|
import javax.swing.border.CompoundBorder;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
|
|
||||||
import org.insa.algo.shortestpath.ShortestPathData;
|
import org.insa.algo.AbstractInputData;
|
||||||
import org.insa.algo.shortestpath.ShortestPathData.Mode;
|
import org.insa.algo.AbstractSolution;
|
||||||
import org.insa.algo.shortestpath.ShortestPathSolution;
|
import org.insa.algo.shortestpath.ShortestPathSolution;
|
||||||
import org.insa.graph.Graph;
|
import org.insa.graph.Graph;
|
||||||
import org.insa.graph.io.BinaryPathWriter;
|
import org.insa.graph.Path;
|
||||||
import org.insa.graphics.drawing.Drawing;
|
import org.insa.graphics.drawing.Drawing;
|
||||||
import org.insa.graphics.drawing.overlays.PathOverlay;
|
import org.insa.graphics.drawing.overlays.PathOverlay;
|
||||||
|
|
||||||
public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeListener, GraphChangeListener {
|
public class SolutionPanel extends JPanel implements DrawingChangeListener, GraphChangeListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private class ShortestPathBundle {
|
private class SolutionBundle {
|
||||||
|
|
||||||
// Solution
|
// Solution
|
||||||
private final ShortestPathSolution solution;
|
private final AbstractSolution solution;
|
||||||
|
|
||||||
// Path Overlay (not final due to redraw)
|
// Path Overlay (not final due to redraw)
|
||||||
private PathOverlay overlay = null;
|
private List<PathOverlay> overlays = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new bundle with the given solution and create a new overlay
|
* Create a new bundle with the given solution and create a new overlay
|
||||||
|
@ -54,72 +51,88 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
|
||||||
* @param solution Solution for this bundle, must not be null.
|
* @param solution Solution for this bundle, must not be null.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public ShortestPathBundle(ShortestPathSolution solution) {
|
public SolutionBundle(AbstractSolution solution) {
|
||||||
this.solution = solution;
|
this.solution = solution;
|
||||||
if (this.solution.isFeasible()) {
|
this.overlays = createOverlaysFromSolution();
|
||||||
this.overlay = drawing.drawPath(this.solution.getPath());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Solution associated with this bundle.
|
* @return Solution associated with this bundle.
|
||||||
*/
|
*/
|
||||||
public ShortestPathSolution getSolution() {
|
public AbstractSolution getSolution() {
|
||||||
return this.solution;
|
return this.solution;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Data assocaited with this bundle.
|
* @return Data assocaited with this bundle.
|
||||||
*/
|
*/
|
||||||
public ShortestPathData getData() {
|
public AbstractInputData getData() {
|
||||||
return this.solution.getInputData();
|
return this.solution.getInputData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Overlay associated with this bundle, or null.
|
* @return Overlays associated with this bundle, or null.
|
||||||
*/
|
*/
|
||||||
public PathOverlay getOverlay() {
|
public List<PathOverlay> getOverlays() {
|
||||||
return this.overlay;
|
return this.overlays;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-draw the current overlay (if any) on the new drawing.
|
* Re-draw the current overlay (if any) on the new drawing.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void updateOverlay(Drawing newDrawing) {
|
public void updateOverlays() {
|
||||||
if (this.overlay != null) {
|
List<PathOverlay> oldOverlays = this.overlays;
|
||||||
PathOverlay oldOverlay = this.overlay;
|
this.overlays = createOverlaysFromSolution();
|
||||||
this.overlay = newDrawing.drawPath(this.solution.getPath());
|
for (int i = 0; i < oldOverlays.size(); ++i) {
|
||||||
this.overlay.setVisible(oldOverlay.isVisible());
|
oldOverlays.get(i).delete();
|
||||||
oldOverlay.delete();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<PathOverlay> createOverlaysFromSolution() {
|
||||||
|
List<PathOverlay> overlays = new ArrayList<>();
|
||||||
|
if (solution.isFeasible()) {
|
||||||
|
Method[] methods = this.solution.getClass().getDeclaredMethods();
|
||||||
|
for (Method method: methods) {
|
||||||
|
if (method.getReturnType().equals(Path.class) && method.getParameterCount() == 0) {
|
||||||
|
try {
|
||||||
|
Path path = (Path) method.invoke(this.solution);
|
||||||
|
overlays.add(drawing.drawPath(path));
|
||||||
|
}
|
||||||
|
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||||
|
// This has been check before, so should never happen...
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return overlays;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
*
|
*
|
||||||
* @see java.lang.Object#toString()
|
* @see java.lang.Object#toString()
|
||||||
*/
|
*/
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Shortest-path from #" + this.getData().getOrigin().getId() + " to #"
|
return getData().toString();
|
||||||
+ this.getData().getDestination().getId() + " [" + this.getData().getMode().toString().toLowerCase()
|
|
||||||
+ "]";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Solution
|
// Solution
|
||||||
private Drawing drawing;
|
private Drawing drawing;
|
||||||
|
|
||||||
// Solution selector
|
// Solution selector
|
||||||
private final JComboBox<ShortestPathBundle> solutionSelect;
|
private final JComboBox<SolutionBundle> solutionSelect;
|
||||||
|
|
||||||
// Map solution -> panel
|
// Map solution -> panel
|
||||||
private final JTextArea informationPanel;
|
private final JTextArea informationPanel;
|
||||||
|
|
||||||
// Current bundle
|
// Current bundle
|
||||||
private ShortestPathBundle currentBundle = null;
|
private SolutionBundle currentBundle = null;
|
||||||
|
|
||||||
public ShortestPathSolutionPanel(Component parent) {
|
public SolutionPanel(Component parent) {
|
||||||
super();
|
super();
|
||||||
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
||||||
setBorder(new CompoundBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.LIGHT_GRAY),
|
setBorder(new CompoundBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, Color.LIGHT_GRAY),
|
||||||
|
@ -147,17 +160,15 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
PathOverlay overlay = currentBundle.getOverlay();
|
for (PathOverlay overlay: currentBundle.getOverlays()) {
|
||||||
if (overlay == null) {
|
if (overlay.isVisible()) {
|
||||||
return;
|
overlay.setVisible(false);
|
||||||
}
|
clearButton.setText("Show");
|
||||||
if (overlay.isVisible()) {
|
}
|
||||||
overlay.setVisible(false);
|
else {
|
||||||
clearButton.setText("Show");
|
overlay.setVisible(true);
|
||||||
}
|
clearButton.setText("Hide");
|
||||||
else {
|
}
|
||||||
overlay.setVisible(true);
|
|
||||||
clearButton.setText("Hide");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -166,26 +177,29 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
|
||||||
saveButton.addActionListener(new ActionListener() {
|
saveButton.addActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
String filepath = System.getProperty("user.dir");
|
// String filepath = System.getProperty("user.dir");
|
||||||
filepath += File.separator + String.format("path_%s_%d_%d.path",
|
// filepath += File.separator + String.format("path_%s_%d_%d.path",
|
||||||
currentBundle.getData().getGraph().getMapId().toLowerCase().replaceAll("[^a-z0-9_]", "_"),
|
// currentBundle.getData().getGraph().getMapId().toLowerCase().replaceAll("[^a-z0-9_]",
|
||||||
currentBundle.getData().getOrigin().getId(), currentBundle.getData().getDestination().getId());
|
// "_"),
|
||||||
JFileChooser fileChooser = new JFileChooser();
|
// currentBundle.getData().getOrigin().getId(),
|
||||||
fileChooser.setSelectedFile(new File(filepath));
|
// currentBundle.getData().getDestination().getId());
|
||||||
fileChooser.setApproveButtonText("Save");
|
// JFileChooser fileChooser = new JFileChooser();
|
||||||
|
// fileChooser.setSelectedFile(new File(filepath));
|
||||||
if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
|
// fileChooser.setApproveButtonText("Save");
|
||||||
File file = fileChooser.getSelectedFile();
|
//
|
||||||
try {
|
// if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
|
||||||
BinaryPathWriter writer = new BinaryPathWriter(
|
// File file = fileChooser.getSelectedFile();
|
||||||
new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))));
|
// try {
|
||||||
writer.writePath(currentBundle.getSolution().getPath());
|
// BinaryPathWriter writer = new BinaryPathWriter(
|
||||||
}
|
// new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))));
|
||||||
catch (IOException e1) {
|
// writer.writePath(currentBundle.getSolution().getPath());
|
||||||
JOptionPane.showMessageDialog(parent, "Unable to write path to the selected file.");
|
// }
|
||||||
e1.printStackTrace();
|
// catch (IOException e1) {
|
||||||
}
|
// JOptionPane.showMessageDialog(parent, "Unable to write path to the selected
|
||||||
}
|
// file.");
|
||||||
|
// e1.printStackTrace();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -200,23 +214,25 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
|
||||||
solutionSelect.addActionListener(new ActionListener() {
|
solutionSelect.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
|
||||||
ShortestPathBundle bundle = (ShortestPathBundle) solutionSelect.getSelectedItem();
|
SolutionBundle bundle = (SolutionBundle) solutionSelect.getSelectedItem();
|
||||||
|
|
||||||
// Handle case when the JComboBox is empty.
|
// Handle case when the JComboBox is empty.
|
||||||
if (bundle == null) {
|
if (bundle == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentBundle != null && currentBundle.getOverlay() != null) {
|
if (currentBundle != null) {
|
||||||
currentBundle.getOverlay().setVisible(false);
|
for (PathOverlay overlay: currentBundle.getOverlays()) {
|
||||||
|
overlay.setVisible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateInformationLabel(bundle);
|
updateInformationLabel(bundle);
|
||||||
buttonPanel.setVisible(bundle.getSolution().isFeasible());
|
buttonPanel.setVisible(bundle.getSolution().isFeasible());
|
||||||
clearButton.setText(bundle.getSolution().isFeasible() ? "Hide" : "Show");
|
clearButton.setText(bundle.getSolution().isFeasible() ? "Hide" : "Show");
|
||||||
|
|
||||||
if (bundle.getOverlay() != null) {
|
for (PathOverlay overlay: bundle.getOverlays()) {
|
||||||
bundle.getOverlay().setVisible(true);
|
overlay.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentBundle = bundle;
|
currentBundle = bundle;
|
||||||
|
@ -226,31 +242,13 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSolution(ShortestPathSolution solution) {
|
public void addSolution(ShortestPathSolution solution) {
|
||||||
ShortestPathBundle bundle = new ShortestPathBundle(solution);
|
SolutionBundle bundle = new SolutionBundle(solution);
|
||||||
solutionSelect.addItem(bundle);
|
solutionSelect.addItem(bundle);
|
||||||
solutionSelect.setSelectedItem(bundle);
|
solutionSelect.setSelectedItem(bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateInformationLabel(ShortestPathBundle bundle) {
|
protected void updateInformationLabel(SolutionBundle bundle) {
|
||||||
ShortestPathData data = bundle.getData();
|
informationPanel.setText(bundle.getSolution().toString());
|
||||||
String info = null;
|
|
||||||
if (!bundle.getSolution().isFeasible()) {
|
|
||||||
info = String.format("No path found from node #%d to node #%d.", data.getOrigin().getId(),
|
|
||||||
data.getDestination().getId());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
info = String.format("Found a path from node #%d to node #%d", data.getOrigin().getId(),
|
|
||||||
data.getDestination().getId());
|
|
||||||
if (data.getMode() == Mode.LENGTH) {
|
|
||||||
info = String.format("%s, %.4f kilometers.", info,
|
|
||||||
(bundle.getSolution().getPath().getLength() / 1000.0));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
info = String.format("%s, %.4f minutes.", info,
|
|
||||||
(bundle.getSolution().getPath().getMinimumTravelTime() / 60.0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
informationPanel.setText(info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -263,19 +261,19 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
|
||||||
solutionSelect.actionPerformed(null);
|
solutionSelect.actionPerformed(null);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ShortestPathBundle bundle = (ShortestPathBundle) this.solutionSelect.getSelectedItem();
|
SolutionBundle bundle = (SolutionBundle) this.solutionSelect.getSelectedItem();
|
||||||
if (bundle != null && bundle.getOverlay() != null) {
|
if (bundle != null) {
|
||||||
bundle.getOverlay().setVisible(false);
|
for (PathOverlay overlay: bundle.getOverlays()) {
|
||||||
|
overlay.setVisible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void newGraphLoaded(Graph graph) {
|
public void newGraphLoaded(Graph graph) {
|
||||||
for (int i = 0; i < this.solutionSelect.getItemCount(); ++i) {
|
for (int i = 0; i < this.solutionSelect.getItemCount(); ++i) {
|
||||||
PathOverlay overlay = this.solutionSelect.getItemAt(i).getOverlay();
|
for (PathOverlay overlay: this.solutionSelect.getItemAt(i).getOverlays()) {
|
||||||
if (overlay != null) {
|
|
||||||
overlay.delete();
|
overlay.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,7 +292,7 @@ public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeLi
|
||||||
@Override
|
@Override
|
||||||
public void onRedrawRequest() {
|
public void onRedrawRequest() {
|
||||||
for (int i = 0; i < this.solutionSelect.getItemCount(); ++i) {
|
for (int i = 0; i < this.solutionSelect.getItemCount(); ++i) {
|
||||||
this.solutionSelect.getItemAt(i).updateOverlay(drawing);
|
this.solutionSelect.getItemAt(i).updateOverlays();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue